New layout pages.
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 5 Sep 2022 23:21:37 +0000 (01:21 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 5 Sep 2022 23:21:37 +0000 (01:21 +0200)
34 files changed:
src/catalogue/templates/catalogue/2022/book_box.html
src/catalogue/templates/catalogue/2022/theme_detail.html [new file with mode: 0644]
src/catalogue/tests/test_tags.py
src/catalogue/views.py
src/club/admin.py
src/club/forms.py
src/club/migrations/0040_amount.py [new file with mode: 0644]
src/club/migrations/0041_move_amounts.py [new file with mode: 0644]
src/club/migrations/0042_auto_20220826_1458.py [new file with mode: 0644]
src/club/models.py
src/club/payment_methods.py
src/club/static/club/payu/banki.png [new file with mode: 0644]
src/club/templates/club/2022/donation_step1.html [new file with mode: 0644]
src/club/templates/club/2022/donation_step2.html [new file with mode: 0644]
src/club/templates/club/2022/donation_step3.html [new file with mode: 0644]
src/club/templates/club/2022/donation_step4.html [new file with mode: 0644]
src/club/templates/club/2022/donation_step_base.html [new file with mode: 0644]
src/club/templates/club/payment/paypal_invite.html [new file with mode: 0644]
src/club/templates/club/payment/payu_invite.html [new file with mode: 0644]
src/club/templates/club/payment_form.html
src/club/templates/payu/rec_widget.html [new file with mode: 0644]
src/club/templatetags/club.py
src/club/urls.py
src/club/views.py
src/paypal/urls.py
src/paypal/views.py
src/wolnelektury/static/2021/scripts/main.js
src/wolnelektury/static/2022/images/checkout-bg.png [new file with mode: 0644]
src/wolnelektury/static/2022/images/checkout-img-4.jpg [new file with mode: 0644]
src/wolnelektury/static/2022/more.scss
src/wolnelektury/static/2022/styles/layout/_module.scss
src/wolnelektury/static/2022/styles/layout/_pagination.scss [new file with mode: 0644]
src/wolnelektury/static/2022/styles/layout/_theme.scss [new file with mode: 0644]
src/wolnelektury/templates/2022/paginate.html [new file with mode: 0644]

index 83b4157..55f851d 100644 (file)
@@ -1,12 +1,12 @@
 {% load sorl_thumbnail %}
 
 <article class="l-books__item" data-pop="{{ book.popularity.count }}">
-  <figure class="l-books__item__img">
+  <figure class="l-books__item__img" style="height:240px">
     <a href="{{ book.get_absolute_url }}">
       {% if book.is_picture %}
         {% if book.image_file %}
-          {% thumbnail book.image_file "170x170" as im %}
-          <img style="float: left; margin:{{ im|margin:"170x170" }}" src="{{ im.url }}" width="{{ im.x }}" height="{{ im.y }}" />
+          {% thumbnail book.image_file "170x240" crop="center" as im %}
+          <img style="float: left; margin:{{ im|margin:"170x240" }}" src="{{ im.url }}" width="{{ im.x }}" height="{{ im.y }}" />
           {% endthumbnail %}
         {% endif %}
       {% else %}
diff --git a/src/catalogue/templates/catalogue/2022/theme_detail.html b/src/catalogue/templates/catalogue/2022/theme_detail.html
new file mode 100644 (file)
index 0000000..622b6b5
--- /dev/null
@@ -0,0 +1,98 @@
+{% extends '2022/base_real.html' %}
+{% load pagination_tags %}
+
+{% block content %}
+  <div class="l-container">
+    <div class="l-breadcrumb">
+      <a href="/"><span>Strona główna</span></a>
+      <a href="/katalog/"><span>Katalog</span></a>
+      <a href="/katalog/motyw/"><span>Motyw</span></a>
+      <span>{{ tags.0.name }}</span>
+    </div>
+  </div>
+
+  <main class="l-main">
+
+    <div class="l-section">
+      <div class="l-author__header">
+        <h1><span>Motyw:</span> {{ tags.0.name }}</h1>
+      </div>
+    </div>
+
+    <!-- div class="l-section">
+         <div class="l-books__header">
+         <div class="l-books__input">
+         <i class="icon icon-filter"></i>
+         <input type="text" placeholder="filtry, tytuł">
+         </div>
+         <div class="l-books__sorting">
+         <span>Sortuj:</span>
+         <div>
+         <button>autorzy</button>
+         <button>epoki</button>
+         <button>gatunki</button>
+         <button>rodzaje</button>
+         <button class="is-active">motywy</button>
+         </div>
+         </div>
+         </div>
+         </div -->
+
+    {% autopaginate object_list 10 %}
+
+    <div class="l-section l-section--col">
+      <div class="l-theme">
+        <div class="l-theme__col">
+          <div class="l-books__col">
+
+            {% for fragment in object_list %}
+              <article class="l-books__item">
+                <figure class="l-books__item__img">
+                  <a href="{{ fragment.get_absolute_url }}">
+                    {% if fragment.book.cover_clean %}
+                      <img src="{{ fragment.book.cover_clean.url }}" alt="{{ fragment.book.title }}">
+                    {% endif %}
+                  </a>
+                </figure>
+                <div class="l-books__item__content">
+                  <div class="l-books__item__actions">
+                    <a href="#" class="icon icon-book-alt"></a>
+                    {% if fragment.book.has_mp3 %}
+                      <a href="#" class="icon icon-audio"></a>
+                    {% endif %}
+                  </div>
+                  <h3>
+                    {% for author in fragment.book.authors %}
+                      <a href="{{ author.get_absolute_url }}">{{ author }}</a>{% if not forloop.last %}, {% endif %}
+                    {% endfor %}
+                  </h3>
+                  <h2><a href="{{ fragment.book.get_absolute_url }}">{{ fragment.book.title }}</a></h2>
+                  <div class="fragment-text">
+                    {{ fragment.short_text|safe }}
+                  </div>
+                  <a href="{{ fragment.get_absolute_url }}">Czytaj więcej</a>
+                </div>
+              </article>
+            {% endfor %}
+            {% paginate using '2022/paginate.html' %}
+          </div>
+        </div>
+        <div class="l-theme__col">
+          <div class="l-theme__info">
+            <h3>Motyw: {{ tags.0.name }}</h3>
+            {{ tags.0.description|safe }}
+            <!--
+                 <h3>Motyw w sztuce <i class="icon icon-arrow-left"></i> <i class="icon icon-arrow-right"></i></h3>
+                 <div class="l-theme__info__slider">
+                 <img src="images/motyw.jpg" alt="">
+                 <img src="images/motyw.jpg" alt="">
+                 <img src="images/motyw.jpg" alt="">
+                 </div>
+            -->
+          </div>
+        </div>
+      </div>
+    </div>
+  </main>
+
+{% endblock %}
index 92845e2..a706618 100644 (file)
@@ -291,4 +291,4 @@ class BookTagsTests(WLTestCase):
         self.assertEqual([t.slug for t in book.tags.filter(category='kind')],
                          ['kind'])
         self.assertEqual([(tag.name, tag.count) for tag in related_themes],
-                         [('ChildTheme', 1), ('ParentTheme', 1), ('Theme', 2)])
+                         [('Theme', 2), ('ChildTheme', 1), ('ParentTheme', 1)])
index 6edbbd6..c63aa7a 100644 (file)
@@ -144,9 +144,12 @@ def object_list(request, objects, fragments=None, related_tags=None, tags=None,
         result.update(extra)
 
     is_author = len(tags) == 1 and tags[0].category == 'author'
+    is_theme = len(tags) == 1 and tags[0].category == 'theme'
     new_layout = request.EXPERIMENTS['layout']
     if is_author and new_layout.value:
         template = 'catalogue/2022/author_detail.html'
+    elif is_theme and new_layout.value:
+        template = 'catalogue/2022/theme_detail.html'
     else:
         template = 'catalogue/tagged_object_list.html'
         
index d966ad6..ce74ec6 100644 (file)
@@ -14,7 +14,20 @@ from wolnelektury.utils import YesNoFilter
 from . import models
 
 
-admin.site.register(models.Club)
+class SingleAmountInline(admin.TabularInline):
+    model = models.SingleAmount
+
+
+class MonthlyAmountInline(admin.TabularInline):
+    model = models.MonthlyAmount
+
+
+@admin.register(models.Club)
+class ClubAdmin(admin.ModelAdmin):
+    inlines = [
+        SingleAmountInline,
+        MonthlyAmountInline
+    ]
 
 
 class PayUOrderInline(admin.TabularInline):
index 3a844da..f919855 100644 (file)
@@ -115,3 +115,84 @@ Twoje dane osobowe nie będą profilowane, ani przesyłane do państw trzecich i
 class PayUCardTokenForm(CardTokenForm):
     def get_queryset(self, view):
         return view.get_schedule().payucardtoken_set
+
+
+
+class DonationStep1Form(forms.ModelForm):
+    switch = forms.CharField()
+    single_amount = forms.IntegerField(required=False)
+    monthly_amount = forms.IntegerField(required=False)
+    single_amount_selected = forms.IntegerField(required=False)
+    monthly_amount_selected = forms.IntegerField(required=False)
+    custom_amount = forms.IntegerField(required=False)
+
+    amount = forms.IntegerField(required=False) # hidden
+
+    class Meta:
+        model = models.Schedule
+        fields = [
+            'amount',
+            'monthly'
+            ]
+
+        
+    def clean(self):
+        state = {}
+        state['monthly'] = self.cleaned_data['switch'] == 'monthly'
+        which = 'monthly' if state['monthly'] else 'single'
+        state['amount'] = \
+            self.cleaned_data[f'{which}_amount'] or \
+            self.cleaned_data['custom_amount'] or \
+            self.cleaned_data[f'{monthly}_amount_selected']
+
+        return state
+
+
+
+class DonationStep2Form(forms.ModelForm, NewsletterForm):
+    class Meta:
+        model = models.Schedule
+        fields = [
+            'first_name', 'last_name',
+            'email', 'phone',
+            'postal',
+            'postal_code', 'postal_town', 'postal_country',
+            ]
+        widgets = {
+            'amount': forms.HiddenInput,
+            'monthly': forms.HiddenInput,
+        }
+    
+    def __init__(self, referer=None, **kwargs):
+        self.referer = referer
+        super().__init__(**kwargs)
+
+        self.fields['first_name'].required = True
+        self.fields['last_name'].required = True
+        self.fields['phone'].required = True
+        
+        self.consent = []
+        for c in models.Consent.objects.filter(active=True).order_by('order'):
+            key = f'consent{c.id}'
+            self.fields[key] = forms.BooleanField(
+                label=c.text,
+                required=c.required
+            )
+            self.consent.append((
+                c, key, (lambda k: lambda: self[k])(key)
+            ))
+
+
+
+    def save(self, *args, **kwargs):
+        NewsletterForm.save(self, *args, **kwargs)
+        self.instance.source = self.referer or ''
+        instance = super().save(*args, **kwargs)
+
+        consents = []
+        for consent, key, consent_field in self.consent:
+            if self.cleaned_data[key]:
+                instance.consent.add(consent)
+
+        return instance
+
diff --git a/src/club/migrations/0040_amount.py b/src/club/migrations/0040_amount.py
new file mode 100644 (file)
index 0000000..1a12155
--- /dev/null
@@ -0,0 +1,38 @@
+# Generated by Django 2.2.27 on 2022-08-26 12:39
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('club', '0039_auto_20220421_0109'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SingleAmount',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('amount', models.IntegerField()),
+                ('description', models.TextField(blank=True)),
+                ('club', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='club.Club')),
+            ],
+            options={
+                'ordering': ['amount'],
+            },
+        ),
+        migrations.CreateModel(
+            name='MonthlyAmount',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('amount', models.IntegerField()),
+                ('description', models.TextField(blank=True)),
+                ('club', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='club.Club')),
+            ],
+            options={
+                'ordering': ['amount'],
+            },
+        ),
+    ]
diff --git a/src/club/migrations/0041_move_amounts.py b/src/club/migrations/0041_move_amounts.py
new file mode 100644 (file)
index 0000000..d920fd0
--- /dev/null
@@ -0,0 +1,40 @@
+# Generated by Django 2.2.27 on 2022-08-26 12:39
+
+from django.db import migrations
+
+
+def move_amounts(apps, schema_editor):
+    Club = apps.get_model('club', 'Club')
+    for club in Club.objects.all():
+        for amount in [int(x) for x in club.single_amounts.split(',')]:
+            club.singleamount_set.create(amount=amount)
+        for amount in [int(x) for x in club.monthly_amounts.split(',')]:
+            club.monthlyamount_set.create(amount=amount)
+
+
+def move_amounts_back(apps, schema_editor):
+    Club = apps.get_model('club', 'Club')
+    for club in Club.objects.all():
+        club.single_amounts = ','.join(
+            str(x) for x in
+            club.singleamount_set.order_by('amount')
+        )
+        club.monthly_amounts = ','.join(
+            str(x) for x in
+            club.monthlyamount_set.order_by('amount')
+        )
+        club.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('club', '0040_amount'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            move_amounts,
+            move_amounts_back
+        )
+    ]
diff --git a/src/club/migrations/0042_auto_20220826_1458.py b/src/club/migrations/0042_auto_20220826_1458.py
new file mode 100644 (file)
index 0000000..187e5eb
--- /dev/null
@@ -0,0 +1,21 @@
+# Generated by Django 2.2.27 on 2022-08-26 12:58
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('club', '0041_move_amounts'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='club',
+            name='monthly_amounts',
+        ),
+        migrations.RemoveField(
+            model_name='club',
+            name='single_amounts',
+        ),
+    ]
index 4f3a8f6..acf131b 100644 (file)
@@ -26,9 +26,7 @@ from . import utils
 class Club(models.Model):
     min_amount = models.IntegerField(_('minimum amount'))
     min_for_year = models.IntegerField(_('minimum amount for year'))
-    single_amounts = models.CharField(_('proposed amounts for single payment'), max_length=255)
     default_single_amount = models.IntegerField(_('default single amount'))
-    monthly_amounts = models.CharField(_('proposed amounts for monthly payments'), max_length=255)
     default_monthly_amount = models.IntegerField(_('default monthly amount'))
 
     class Meta:
@@ -37,12 +35,23 @@ class Club(models.Model):
     
     def __str__(self):
         return 'Klub'
-    
-    def proposed_single_amounts(self):
-        return [int(x) for x in self.single_amounts.split(',')]
 
-    def proposed_monthly_amounts(self):
-        return [int(x) for x in self.monthly_amounts.split(',')]
+
+class SingleAmount(models.Model):
+    club = models.ForeignKey(Club, models.CASCADE)
+    amount = models.IntegerField()
+    description = models.TextField(blank=True)
+
+    class Meta:
+        ordering = ['amount']
+
+class MonthlyAmount(models.Model):
+    club = models.ForeignKey(Club, models.CASCADE)
+    amount = models.IntegerField()
+    description = models.TextField(blank=True)
+
+    class Meta:
+        ordering = ['amount']
 
 
 class Consent(models.Model):
@@ -116,6 +125,13 @@ class Schedule(models.Model):
     def get_payment_method(self):
         return [m for m in methods if m.slug == self.method][0]
 
+    def get_payment_methods(self):
+        for method in methods:
+            if (self.monthly or self.yearly) and method.is_recurring:
+                yield method
+            elif not (self.monthly or self.yearly) and method.is_onetime:
+                yield method
+
     def is_expired(self):
         return self.expires_at is not None and self.expires_at <= now()
 
index e74ae83..9fddff3 100644 (file)
@@ -1,10 +1,14 @@
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+from hashlib import sha256
 from django.conf import settings
 from django.urls import reverse
 from django.utils.timezone import now
+from django.utils.translation import get_language
 from paypal.rest import agreement_approval_url
+from django.template.loader import render_to_string
+from .payu import POSS
 
 
 class PaymentMethod(object):
@@ -28,6 +32,14 @@ class PayU(PaymentMethod):
     def __init__(self, pos_id):
         self.pos_id = pos_id
 
+    def invite_widget(self, schedule):
+        return render_to_string(
+            'club/payment/payu_invite.html',
+            {
+                'schedule': schedule,
+            }
+        )
+
     def initiate(self, request, schedule):
         # Create Order at once.
         from .models import PayUOrder
@@ -54,6 +66,36 @@ class PayURe(PaymentMethod):
     def initiate(self, request, schedule):
         return reverse('club_payu_rec_payment', args=[schedule.key])
 
+    def invite_widget(self, schedule):
+        from . import forms
+        pos = POSS[self.pos_id]
+        widget_args = {
+            'merchant-pos-id': pos.pos_id,
+            'shop-name': "SHOW NAME",
+            'total-amount': str(int(schedule.amount * 100)),
+            'currency-code': pos.currency_code,
+            'customer-language': get_language(), # filter to pos.languages
+            'customer-email': schedule.email,
+            'store-card': 'true',
+            'recurring-payment': 'true',
+        }
+        widget_sig = sha256(
+            (
+                "".join(v for (k, v) in sorted(widget_args.items())) +
+                pos.secondary_key
+            ).encode('utf-8')
+        ).hexdigest()
+        
+        return render_to_string(
+            'payu/rec_widget.html',
+            {
+                'form': forms.PayUCardTokenForm(),
+                'pos': POSS[self.pos_id],
+                'widget_args': widget_args,
+                'widget_sig': widget_sig,
+            }
+        )
+    
     def pay(self, request, schedule):
         # Create order, put it and see what happens next.
         from .models import PayUOrder
@@ -104,6 +146,14 @@ class PayPal(PaymentMethod):
     is_recurring = True
     is_onetime = False
 
+    def invite_widget(self, schedule):
+        return render_to_string(
+            'club/payment/paypal_invite.html',
+            {
+                'schedule': schedule,
+            }
+        )
+    
     def initiate(self, request, schedule):
         app = request.GET.get('app')
         return agreement_approval_url(schedule.amount, schedule.key, app=app)
diff --git a/src/club/static/club/payu/banki.png b/src/club/static/club/payu/banki.png
new file mode 100644 (file)
index 0000000..528ce8b
Binary files /dev/null and b/src/club/static/club/payu/banki.png differ
diff --git a/src/club/templates/club/2022/donation_step1.html b/src/club/templates/club/2022/donation_step1.html
new file mode 100644 (file)
index 0000000..057ab41
--- /dev/null
@@ -0,0 +1,139 @@
+{% extends 'club/2022/donation_step_base.html' %}
+{% load club %}
+{% load static %}
+
+
+{% block donation-step-content %}
+  <form method="post">
+    {% csrf_token %}
+    {{ form.errors }}
+    <input type="radio" name="switch" id="switch-once" value="single" class="toggle-input" {% if schedule and not schedule.monthly %}checked{% endif %}>
+    <input type="radio" name="switch" id="switch-monthly" value="monthly" class="toggle-input" {% if not schedule or schedule.monthly %}checked{% endif %}>
+    <div class="l-switch__wrapper">
+
+      <div class="l-switch white">
+        <label class='toggle-for' for="switch-once">Jednorazowo</label>
+        <label class='toggle-for' for="switch-monthly">Miesięcznie</label>
+        <span class="toggle"></span>
+          </div>
+        </div>
+
+        <div class="l-checkout__payments payments-once">
+          {% for amount in club.singleamount_set.all %}
+            <div class="l-checkout__payments__box once{% if not schedule.monthly and schedule.amount == amount.amount or not schedule and club.default_single_amount == amount.amount %} is-active{% endif %}{% if forloop.last %} l-checkout__payments__box--xl{% endif %}">
+              <div>
+                <h3>{{ amount.amount }} zł</h3>
+                <div class="l-checkout__payments__box__btn-wrp">
+                  <button name="single_amount" value="{{ amount.amount }}">Wybierz</button>
+                </div>
+              </div>
+              {% if amount.description %}
+                <div>
+                  <p>{{ amount.description|safe }}</p>
+                </div>
+              {% endif %}
+            </div>
+          {% endfor %}
+          <input type="hidden"
+                 name="single_amount_selected"
+                 value="{% if schedule and not schedule.monthly %}{{ schedule.amount|floatformat }}{% else %}{{ club.default_single_amount }}{% endif %}">
+
+        </div>
+
+
+        <div class="l-checkout__payments payments-recurring">
+          {% for amount in club.monthlyamount_set.all %}
+            <div class="l-checkout__payments__box{% if schedule.monthly and schedule.amount == amount.amount or not schedule and amount.amount == club.default_monthly_amount %} is-active{% endif %}">
+              <h3>{{ amount.amount }} zł <span>/mies.</span></h3>
+              <div class="l-checkout__payments__box__btn-wrp">
+                <p>{{ amount.description|safe }}</p>
+                <button name="monthly_amount" value="{{ amount.amount }}">Wybierz</button>
+              </div>
+            </div>
+          {% endfor %}
+          <input type="hidden"
+                 name="monthly_amount_selected"
+                 value="{% if schedule and schedule.monthly %}{{ schedule.amount|floatformat }}{% else %}{{ club.default_monthly_amount }}{% endif %}">
+        </div>
+
+        <div class="l-checkout__amount">
+          <div class="l-checkout__input">
+            <label for="kwota">Inna kwota</label>
+            <!-- input type="text" id="kwota" name="custom_amount" value="" -->
+            {{ form.custom_amount }}
+          </div>
+          <button>Dalej</button>
+        </div>
+      </form>
+
+      <img src="{% static '2022/images/checkout-footer.png' %}" alt="Bezpieczne płatności zapewniają" class="l-checkout__footer__img">
+      <div class="l-checkout__cols bt-w">
+        <div class="l-checkout__col full">
+          <div class="l-checkout__form">
+            <div class="l-checkout__form__row full">
+              <h3>Dane do przelewu tradycyjnego:</h3>
+              <div class="l-checkout__info">
+                <div class="l-checkout__info__item">
+                  <div>nazwa odbiorcy</div>
+                  <h3>Fundacja Nowoczesna Polska</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="Fundacja Nowoczesna Polska">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>adres odbiorcy</div>
+                  <h3>ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>numer konta</div>
+                  <h3>75 1090 2851 0000 0001 4324 3317</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="75 1090 2851 0000 0001 4324 3317">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>tytuł przelewu</div>
+                  <h3>Darowizna na Wolne Lektury + twoja nazwa użytkownika lub e-mail</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="Darowizna na Wolne Lektury + twoja nazwa użytkownika lub e-mail">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>wpłaty w EUR</div>
+                  <h3>PL88 1090 2851 0000 0001 4324 3374</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="PL88 1090 2851 0000 0001 4324 3374">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>Wpłaty w USD</div>
+                  <h3>PL82 1090 2851 0000 0001 4324 3385</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="PL88 1090 2851 0000 0001 4324 3374">
+                </div>
+                <div class="l-checkout__info__item">
+                  <div>SWIFT</div>
+                  <h3>WBKPPLPP</h3>
+                  <button title="Kopiuj tekst" class="js-copy">
+                    <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+                  </button>
+                  <input type="text" value="WBKPPLPP">
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+{% endblock %}
diff --git a/src/club/templates/club/2022/donation_step2.html b/src/club/templates/club/2022/donation_step2.html
new file mode 100644 (file)
index 0000000..cd7a9f4
--- /dev/null
@@ -0,0 +1,109 @@
+{% extends 'club/2022/donation_step_base.html' %}
+
+{% load static %}
+
+
+{% block donation-jumbo-image %}{% static '2022/images/checkout-img-2.jpg' %}{% endblock %}
+
+
+{% block donation-step-content %}
+
+  <div class="l-checkout__cols">
+    <div class="l-checkout__col">
+      <div class="l-checkout__payments__box is-active">
+        <h3>
+          {{ schedule.amount|floatformat }} zł
+          {% if schedule.monthly %}
+            <span>/mies.</span>
+          {% endif %}
+        </h3>
+        <img src="{% static '2022/images/checkout-img-3.jpg' %}" alt="">
+      </div>
+    </div>
+    <div class="l-checkout__col">
+
+      <form method='post'>
+        {% csrf_token %}
+        {{ form.errors }}
+        {{ form.amount }}
+        {{ form.monthly }}
+        <div class="l-checkout__form">
+          <div class="l-checkout__form__row">
+            <div class="l-checkout__input">
+              <label for="imie"><span>*</span> Imię</label>
+              {{ form.first_name }}
+              {{ form.first_name.errors }}
+            </div>
+            <div class="l-checkout__input">
+              <label for="nazwisko"><span>*</span> Nazwisko</label>
+              {{ form.last_name }}
+              {{ form.last_name.errors }}
+            </div>
+          </div>
+          <div class="l-checkout__form__row">
+            <div class="l-checkout__input">
+              <label for="email"><span>*</span> E-mail</label>
+              {{ form.email }}
+              {{ form.email.errors }}
+            </div>
+            <div class="l-checkout__input">
+              <label for="telefon"><span>*</span> Telefon</label>
+              {{ form.phone }}
+              {{ form.phone.errors }}
+            </div>
+          </div>
+          <div class="l-checkout__form__row full">
+            <div class="l-checkout__input">
+              <label for="adres-pocztowy">Adres pocztowy</label>
+              {{ form.postal }}
+              {{ form.postal.errors }}
+            </div>
+          </div>
+          <div class="l-checkout__form__row">
+            <div class="l-checkout__input">
+              <label for="kod-pocztowy">Kod pocztowy</label>
+              {{ form.postal_code }}
+              {{ form.postal_code.errors }}
+            </div>
+            <div class="l-checkout__input">
+              <label for="miejscowosc">Miejscowość</label>
+              {{ form.postal_town }}
+              {{ form.postal_town.errors }}
+            </div>
+          </div>
+          <div class="l-checkout__form__row full">
+            <div class="l-checkout__input">
+              <label for="kod-pocztowy">Kraj</label>
+              {{ form.postal_country }}
+              {{ form.postal_country.errors }}
+            </div>
+          </div>
+          <div class="l-checkout__form__row full">
+            {% for consent, key, field in form.consent %}
+              {{ field.errors }}
+              <div class="c-checkbox">
+                {{ field }}
+                <label for="id_{{ key }}">
+                  <p>{% if field.field.required %}<span>*</span> {% endif %}{{ field.label }}</p>
+                </label>
+              </div>
+            {% endfor %}
+            <div class="c-checkbox">
+              {{ form.agree_newsletter }}
+              <label for="id_agree_newsletter">
+                <p>Zapisuję się na newsletter.</p>
+              </label>
+            </div>
+          </div>
+          <div class="l-checkout__form__row confirm">
+            <a href=".#{{ view.step1_hash }}">Powrót</a>
+            <div class="l-checkout__input">
+              <button>Dalej</button>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+  </div>
+  <img src="{% static '2022/images/checkout-footer.png' %}" alt="Bezpieczne płatności zapewniają" class="l-checkout__footer__img">
+{% endblock %}
diff --git a/src/club/templates/club/2022/donation_step3.html b/src/club/templates/club/2022/donation_step3.html
new file mode 100644 (file)
index 0000000..4da3456
--- /dev/null
@@ -0,0 +1,103 @@
+{% extends 'club/2022/donation_step_base.html' %}
+
+{% load static %}
+{% load club %}
+
+
+{% block donation-jumbo-image %}{% static '2022/images/checkout-img-4.jpg' %}{% endblock %}
+
+
+{% block donation-step-content %}
+  <div class="l-checkout__cols">
+    <div class="l-checkout__col">
+      <div class="l-checkout__payments__box is-active">
+        <h3>
+          {{ schedule.amount|floatformat }} zł
+          {% if schedule.monthly %}
+            <span>/mies.</span>
+        {% endif %}</h3>
+        <img src="{% static '2022/images/checkout-img-3.jpg' %}" alt="">
+      </div>
+    </div>
+    <div class="l-checkout__col">
+      <div class="l-checkout__form">
+        <div class="l-checkout__form__row full">
+          <!-- h3>Wybierz bezpieczną płatność:</h3-->
+          <div class="iframe">
+            {% for method in schedule.get_payment_methods %}
+              {% invite_payment method schedule %}
+            {% endfor %}
+          </div>
+        </div>
+        <div class="l-checkout__form__row full">
+          <h3>Możesz też ustawić stały przelew na konto:</h3>
+          <div class="l-checkout__info">
+            <div class="l-checkout__info__item">
+              <div>nazwa odbiorcy</div>
+              <h3>Fundacja Nowoczesna Polska</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="Fundacja Nowoczesna Polska">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>adres odbiorcy</div>
+              <h3>ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>numer konta</div>
+              <h3>75 1090 2851 0000 0001 4324 3317</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="75 1090 2851 0000 0001 4324 3317">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>tytuł przelewu</div>
+              <h3>Darowizna na Wolne Lektury + twoja nazwa użytkownika lub e-mail</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="Darowizna na Wolne Lektury + twoja nazwa użytkownika lub e-mail">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>wpłaty w EUR</div>
+              <h3>PL88 1090 2851 0000 0001 4324 3374</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="PL88 1090 2851 0000 0001 4324 3374">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>Wpłaty w USD</div>
+              <h3>PL82 1090 2851 0000 0001 4324 3385</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="PL88 1090 2851 0000 0001 4324 3374">
+            </div>
+            <div class="l-checkout__info__item">
+              <div>SWIFT</div>
+              <h3>WBKPPLPP</h3>
+              <button title="Kopiuj tekst" class="js-copy">
+                <img src="{% static '2022/images/copy.svg' %}" alt="Kopiuj">
+              </button>
+              <input type="text" value="WBKPPLPP">
+            </div>
+          </div>
+        </div>
+        <div class="l-checkout__form__row confirm">
+          <a href="#">Powrót</a>
+          <!-- div class="l-checkout__input">
+            <a href="#">Dalej</a>
+          </div-->
+        </div>
+      </div>
+    </div>
+  </div>
+  <img src="{% static '2022/images/checkout-footer.png' %}" alt="Bezpieczne płatności zapewniają" class="l-checkout__footer__img">
+{% endblock %}
diff --git a/src/club/templates/club/2022/donation_step4.html b/src/club/templates/club/2022/donation_step4.html
new file mode 100644 (file)
index 0000000..f257111
--- /dev/null
@@ -0,0 +1,15 @@
+{% extends 'club/2022/donation_step_base.html' %}
+
+
+{% block donation-step-content %}
+  <div class="l-checkout__completed">
+    <div class="l-checkout__completed__wrapper">
+      <h1>Dziękujemy za wpłatę!</h1>
+      <p>
+        Zajrzyj teraz do e-maila. Tam znajdziesz link,
+        który powiąże płatność z Twoim kontem użytkownika Wolnych Lektur.
+      </p>
+      <a href="#">Wracam do lektur</a>
+    </div>
+  </div>
+{% endblock %}
diff --git a/src/club/templates/club/2022/donation_step_base.html b/src/club/templates/club/2022/donation_step_base.html
new file mode 100644 (file)
index 0000000..976b13c
--- /dev/null
@@ -0,0 +1,130 @@
+{% extends '2022/base.html' %}
+{% load club %}
+{% load static %}
+
+
+{% block content %}
+  <div class="l-container">
+    <div class="l-breadcrumb">
+      <a href="#"><span>Strona główna</span></a>
+      <a href="#"><span>Wesprzyj nas</span></a>
+    </div>
+  </div>
+
+
+  <main class="l-main">
+    <div class="l-checkout__support">
+      <div class="l-checkout__support__bar">
+        <span data-label="Jest nas {% club_count_recurring %}" style="width: calc({% club_count_recurring %}% / 10);"></span>
+      </div>
+      <div class="l-checkout__support__footer">
+        <p>Dołącz do naszych stałych <strong>darczyńców</strong>!</p>
+        <p>Minimalną stabilność uzyskamy przy <strong>1000</strong> regularnych darczyńców!</p>
+      </div>
+    </div>
+
+    <div class="l-checkout__box">
+      <div class="l-checkout__box__header">
+        <img src="{% block donation-jumbo-image %}{% static '2022/images/checkout-img-1.jpg' %}{% endblock %}" alt="Wspieraj Wolne Lektury">
+        <div class="l-checkout__box__header__content">
+          <h1>Wspieraj Wolne Lektury</h1>
+          <p>Dziękujemy, że chcesz razem z nami uwalniać książki!</p>
+          <p>Wspieraj Wolne Lektury stałą wpłatą – nawet niewielka ma wielką moc! Możesz też wesprzeć Wolne Lektury jednorazowo.</p>
+        </div>
+      </div>
+      <div class="l-checkout__steps">
+
+        {% if view.step > 1 and view.step != 4 %}
+          <a href="{% url 'donation_step1' schedule.key %}">
+        {% endif %}
+        <div class="{% if view.step == 1 %}is-current{% else %}is-completed{% endif %}">
+          <span>1</span>
+          <p>Rodzaj wsparcia</p>
+        </div>
+        {% if view.step > 1 and view.step != 4 %}
+          </a>
+        {% endif %}
+
+        {% if view.step != 2 and schedule and view.step != 4 %}
+          <a href="{% url 'donation_step2' schedule.key %}">
+        {% endif %}
+        <div class="{% if view.step == 2 %}is-current{% elif not schedule %}is-inactive{% else %}is-completed{% endif %}">
+          <span>2</span>
+          <p>Dane</p>
+        </div>
+        {% if view.step != 2 and schedule and view.step != 4 %}
+          </a>
+        {% endif %}
+
+        {% if view.step != 3 and schedule.email and view.step != 4 %}
+          <a href="{{ schedule.get_absolute_url }}">
+        {% endif %}
+        <div class="{% if view.step == 3 %}is-current{% elif not schedule or not schedule.method %}is-inactive{% else %}is-completed{% endif %}">
+          <span>3</span>
+          <p>Forma płatności</p>
+        </div>
+        {% if view.step != 3 and schedule.email and view.step != 4 %}
+          </a>
+        {% endif %}
+
+        <div class="{% if view.step == 4 %}is-completed{% else %}is-inactive{% endif %}">
+          <span>4</span>
+          <p>Gotowe</p>
+        </div>
+      </div>
+
+
+      {% block donation-step-content %}{% endblock %}
+
+    </div>
+
+    <div class="l-checkout__footer">
+      <div class="l-checkout__footer__content">
+        <div class="l-checkout__footer__content__item">
+          <h3>Transparentność jest dla nas bardzo ważna.</h3>
+          <div>
+            <div class="l-article__overlay" data-max-height="91">
+              <p>
+                O tym, jak wydajemy pozyskane pieniądze, dowiesz się ze sprawozdań finansowych i merytorycznych, które znajdziesz na naszej stronie lub w bazie Narodowego Instytutu Wolności, wpisując nr KRS 0000070056.
+              </p>
+            </div>
+          </div>
+        </div>
+        <div class="l-checkout__footer__content__item">
+          <h3>Informacja o przetwarzaniu danych osobowych</h3>
+          <div>
+            <div class="l-article__overlay" data-max-height="91">
+              <p>
+                W każdej chwili możesz zrezygnować z subskrypcji. <a href="#">Więcej informacji. Polityka prywatności.</a>
+                Administratorem Twoich danych osobowych jest Fundacja Nowoczesna Polska z siedzibą w Warszawie, przy ul. Marszałkowskiej 84/92 lok. 125, 00-514 Warszawa (dalej: Fundacja).
+              </p>
+              <p>
+                Lorem ipsum dolor sit amet, consectetur adipisicing elit. A alias consequatur deserunt doloribus facilis, ipsum nisi nulla quam rem totam!
+                Lorem ipsum dolor sit amet, consectetur adipisicing elit. A alias consequatur deserunt doloribus facilis, ipsum nisi nulla quam rem totam!
+              </p>
+              <p>
+                Lorem ipsum dolor sit amet, consectetur adipisicing elit. A alias consequatur deserunt doloribus facilis, ipsum nisi nulla quam rem totam!
+                Lorem ipsum dolor sit amet, consectetur adipisicing elit. A alias consequatur deserunt doloribus facilis, ipsum nisi nulla quam rem totam!
+              </p>
+            </div>
+            <button class="l-article__read-more" aria-label="Kliknij aby rozwinąć" data-label="Więcej" data-action="Mniej">Więcej</button>
+          </div>
+        </div>
+        <div class="l-checkout__footer__content__item">
+          <h3>FAQ</h3>
+          <div>
+            <div class="l-article__overlay" data-max-height="91">
+              <p>
+                Chcesz zmienić wysokość darowizny, anulować przyszłe płatności lub masz inne pytania? Tu znajdziesz odpowiedzi na nie:
+                <a href="#">Pytania i odpowiedzi dotyczące płatności</a>.
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </main>
+
+
+
+{% endblock %}
diff --git a/src/club/templates/club/payment/paypal_invite.html b/src/club/templates/club/payment/paypal_invite.html
new file mode 100644 (file)
index 0000000..6a29097
--- /dev/null
@@ -0,0 +1,7 @@
+{% load static %}
+<h3>Wolisz wpłacić przez PayPal?</h3>
+<a href="{% url 'paypal_init' schedule.key %}">
+  <div class="iframe">
+    <img src="{% static 'club/paypal.png' %}" alt="PayPal">
+  </div>
+</a>
diff --git a/src/club/templates/club/payment/payu_invite.html b/src/club/templates/club/payment/payu_invite.html
new file mode 100644 (file)
index 0000000..8c16c51
--- /dev/null
@@ -0,0 +1,5 @@
+{% load static %}
+<a href="{% url 'club_payu_payment' schedule.key %}">
+       <h3>Przejdź do płatności &rarr;</h3>
+  <img src="{% static 'club/payu/banki.png' %}" style="width: 100%">
+</a>
index 58d564c..a5b5c06 100644 (file)
@@ -28,8 +28,8 @@
 <h3>2. {% trans "Choose the amount" %}</h3>
 
 <div class="plan" id="plan-single" style="display:none;" data-monthly="False" data-min-for-year="{{ club.min_for_year }}" data-amount="{{ club.default_single_amount }}">
-  {% for amount in club.proposed_single_amounts %}
-    <span class="button kwota{% if amount == club.default_single_amount %} active{% endif %}{% if amount >= club.min_for_year %} yearly{% endif %}">{{ amount }}</span>
+  {% for amount in club.singleamount_set.all %}
+    <span class="button kwota{% if amount.amount == club.default_single_amount %} active{% endif %}{% if amount.amount >= club.min_for_year %} yearly{% endif %}">{{ amount.amount }}</span>
   {% endfor %}
 
   <span class="inna">
@@ -41,8 +41,8 @@
 
 
 <div class="plan" id="plan-monthly" data-monthly="True" data-amount="{{ club.default_monthly_amount }}">
-  {% for amount in club.proposed_monthly_amounts %}
-    <span class="button kwota{% if amount == club.default_monthly_amount %} active{% endif %}">{{ amount }}</span>
+  {% for amount in club.monthlyamount_set.all %}
+    <span class="button kwota{% if amount.amount == club.default_monthly_amount %} active{% endif %}">{{ amount.amount }}</span>
   {% endfor %}
 
   <span class="inna">
diff --git a/src/club/templates/payu/rec_widget.html b/src/club/templates/payu/rec_widget.html
new file mode 100644 (file)
index 0000000..89b114b
--- /dev/null
@@ -0,0 +1,26 @@
+<h3>Podaj dane karty płatniczej</h3>
+<div class="iframe">
+  <form id="theform" method='POST'>
+    {% csrf_token %}
+    {{ form }}
+  </form>
+
+  <script>
+   function paymentcallback(data) {
+       $("#theform #id_token").val(data.value);
+       $("#theform").submit()
+   }
+  </script>
+
+  <div id="payu-widget"></div>
+  <script
+      src="{{ pos.get_api_host }}/front/widget/js/payu-bootstrap.js"
+
+      {% for k, v in widget_args.items %}
+          {{ k }}="{{ v }}"
+      {% endfor %}
+
+      success-callback="paymentcallback"
+      sig="{{ widget_sig }}">
+  </script>
+</div>
index d691297..be7dda9 100644 (file)
@@ -78,3 +78,8 @@ def club_monthly_since(start):
 def club_monthly_missing_since(start, target):
     return target - Schedule.objects.filter(
         monthly=True, payed_at__gte=start).count()
+
+
+@register.simple_tag
+def invite_payment(payment_method, schedule):
+    return payment_method.invite_widget(schedule)
index 9b9d897..28cf959 100644 (file)
@@ -16,6 +16,8 @@ urlpatterns = [
     path('plan/<key>/', banner_exempt(views.ScheduleView.as_view()), name='club_schedule'),
     path('plan/<key>/dziekujemy/', banner_exempt(views.ScheduleThanksView.as_view()), name='club_thanks'),
     path('plan/<key>/zestawienie/<int:year>/', banner_exempt(views.YearSummaryView.as_view()), name='club_year_summary'),
+    path('plan/<key>/rodzaj/', banner_exempt(views.DonationStep1.as_view()), name='donation_step1'),
+    path('plan/<key>/dane/', banner_exempt(views.DonationStep2.as_view()), name='donation_step2'),
 
     path('przylacz/<key>/', views.claim, name='club_claim'),
     path('anuluj/<key>/', views.cancel, name='club_cancel'),
index 74d86de..74ff2fb 100644 (file)
@@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required, permission_required
 from django.db.models import Sum
 from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render
+from django.urls import reverse
 from django.utils.decorators import method_decorator
 from django.views.decorators.cache import never_cache
 from django.views.generic import FormView, CreateView, TemplateView, DetailView, UpdateView
@@ -13,6 +14,7 @@ from django.views import View
 from .payu import POSS
 from .payu import views as payu_views
 from .forms import ScheduleForm, PayUCardTokenForm
+from . import forms
 from . import models
 from .helpers import get_active_schedule
 from .payment_methods import recurring_payment_method
@@ -27,15 +29,54 @@ class ClubView(TemplateView):
         return ctx
 
 
-class JoinView(CreateView):
-    form_class = ScheduleForm
-    template_name = 'club/membership_form.html'
 
+class DonationStep1(UpdateView):
+    queryset = models.Schedule.objects.filter(payed_at=None)
+    form_class = forms.DonationStep1Form
+    slug_field = slug_url_kwarg = 'key'
+    template_name = 'club/2022/donation_step1.html'
+    step = 1
+
+    def get_context_data(self, **kwargs):
+        c = super().get_context_data(**kwargs)
+        c['club'] = models.Club.objects.first()
+        return c
+
+    def get_success_url(self):
+        return reverse('donation_step2', args=[self.object.key])
+
+
+class DonationStep2(UpdateView):
+    queryset = models.Schedule.objects.filter(payed_at=None)
+    form_class = forms.DonationStep2Form
+    slug_field = slug_url_kwarg = 'key'
+    template_name = 'club/2022/donation_step2.html'
+    step = 2
+
+
+class JoinView(CreateView):
+    @property
+    def club(self):
+        return models.Club.objects.first()
+
+    @property
+    def new_layout(self):
+        return self.request.EXPERIMENTS['layout'].value
+    
+    def get_template_names(self):
+        if self.new_layout:
+            return 'club/2022/donation_step1.html'
+        return 'club/membership_form.html'
+
+    def get_form_class(self):
+        if self.new_layout:
+            return forms.DonationStep1Form
+        return ScheduleForm
+    
     def is_app(self):
         return self.request.GET.get('app')
 
     def get(self, request):
-        # TODO: configure as app-allowed hosts.
         if settings.CLUB_APP_HOST and self.is_app() and request.META['HTTP_HOST'] != settings.CLUB_APP_HOST:
             return HttpResponseRedirect("https://" + settings.CLUB_APP_HOST + request.get_full_path())
 
@@ -43,7 +84,8 @@ class JoinView(CreateView):
             request.session['from_app'] = True
         elif request.session and 'from_app' in request.session:
             del request.session['from_app']
-        return super(JoinView, self).get(request)
+
+        return super().get(request)
 
     def get_context_data(self, **kwargs):
         c = super(JoinView, self).get_context_data(**kwargs)
@@ -57,12 +99,13 @@ class JoinView(CreateView):
     def get_initial(self):
         if self.request.user.is_authenticated and self.request.user.email:
             return {
-                'email': self.request.user.email,
+                'email': self.request.user.email
             }
 
     def get_form_kwargs(self):
         kwargs = super().get_form_kwargs()
-        kwargs['referer'] = self.request.META.get('HTTP_REFERER', '')
+        if not self.new_layout:
+            kwargs['referer'] = self.request.META.get('HTTP_REFERER', '')
         return kwargs
 
     def form_valid(self, form):
@@ -73,15 +116,24 @@ class JoinView(CreateView):
         return retval
 
     def get_success_url(self):
+        if self.new_layout:
+            return reverse('donation_step2', args=[self.object.key])
         return self.object.initiate_payment(self.request)
 
 
 @method_decorator(never_cache, name='dispatch')
 class ScheduleView(DetailView):
-    model = models.Schedule
+    queryset = models.Schedule.objects.exclude(email='')
     slug_field = slug_url_kwarg = 'key'
     template_name = 'club/schedule.html'
-
+    step = 3
+    
+    def get_template_names(self):
+        if self.request.EXPERIMENTS['layout'].value:
+            if not self.object.payed_at:
+                return 'club/2022/donation_step3.html'
+        return 'club/schedule.html'
+        
     def get_context_data(self, *args, **kwargs):
         ctx = super().get_context_data(*args, **kwargs)
         ctx['active_menu_item'] = 'club'
@@ -118,6 +170,7 @@ class DummyPaymentView(TemplateView):
     def post(self, request, key):
         schedule = models.Schedule.objects.get(key=key)
         schedule.create_payment()
+
         return HttpResponseRedirect(schedule.get_absolute_url())
 
 
@@ -127,6 +180,8 @@ class PayUPayment(DetailView):
 
     def get(self, request, key):
         schedule = self.get_object()
+        schedule.method = 'payu'
+        schedule.save(update_fields=['method'])
         return HttpResponseRedirect(schedule.initiate_payment(request))
 
 
@@ -142,7 +197,10 @@ class PayURecPayment(payu_views.RecPayment):
         return POSS[pos_id]
 
     def get_success_url(self):
-        return self.get_schedule().pay(self.request)
+        schedule = self.get_schedule()
+        schedule.method = 'payu-re'
+        schedule.save(update_fields=['method'])
+        return schedule.pay(self.request)
 
 
 class PayUNotifyView(payu_views.NotifyView):
@@ -152,8 +210,13 @@ class PayUNotifyView(payu_views.NotifyView):
 class ScheduleThanksView(DetailView):
     model = models.Schedule
     slug_field = slug_url_kwarg = 'key'
-    template_name = 'club/thanks.html'
+    step = 4
 
+    def get_template_names(self):
+        if self.request.EXPERIMENTS['layout'].value:
+            return 'club/2022/donation_step4.html'
+        return 'club/thanks.html'
+    
     def get_context_data(self, *args, **kwargs):
         ctx = super().get_context_data(*args, **kwargs)
         ctx['active_menu_item'] = 'club'
index 7c4f693..cc4523f 100644 (file)
@@ -9,6 +9,7 @@ urlpatterns = (
     path('form/', RedirectView.as_view(url='/pomagam/')),
     path('app-form/', RedirectView.as_view(url='/pomagam/?pk_campaign=aplikacja')),
 
+    path('init/<key>/', views.paypal_init, name='paypal_init'),
     path('return/<key>/', views.paypal_return, name='paypal_return'),
     path('app-return/<key>/', views.paypal_return, kwargs={'app': True}, name='paypal_app_return'),
     path('cancel/', views.paypal_cancel, name='paypal_cancel'),
index b1720f9..b5640c4 100644 (file)
@@ -6,7 +6,7 @@ from decimal import Decimal
 from django.contrib.auth.decorators import login_required
 from django.http import Http404
 from django.http.response import HttpResponseRedirect, HttpResponseForbidden
-from django.shortcuts import get_object_or_404, render
+from django.shortcuts import get_object_or_404, render, redirect
 
 from api.utils import HttpResponseAppRedirect
 from club.models import Schedule
@@ -32,6 +32,14 @@ def paypal_form(request, app=False):
     return render(request, 'paypal/form.html', {'form': form})
 
 
+def paypal_init(request, key):
+    schedule = get_object_or_404(Schedule, key=key)
+    schedule.method = 'paypal'
+    schedule.save(update_fields=['method'])
+    app = request.GET.get('app')
+    return redirect(agreement_approval_url(schedule.amount, schedule.key, app=app))
+
+
 @login_required
 def paypal_return(request, key, app=False):
     schedule = get_object_or_404(Schedule, key=key)
index 99a7fc7..1ffea17 100644 (file)
 
 })();
 
-//Switch
 (function() {
-  let $switchOnce = $('#switch-once');
-  let $switchMonthly = $('#switch-monthly');
-
-  $switchMonthly.on('click', function() {
-      $('.payments-once').hide();
-      $('.payments-recurring').show();
-  });
-
-  $switchOnce.on('click', function() {
-      $('.payments-recurring').hide();
-      $('.payments-once').show();
-  });
-})();
-
-
-(function() {
-
     $('.l-checkout__payments__box button').on('click', function() {
         let container = $(this).closest('.l-checkout__payments');
-        $('input', container).val($(this).attr('data-amount'));
+        $('input', container).val($(this).val());
         $('.is-active', container).removeClass('is-active');
         $(this).closest('.l-checkout__payments__box').addClass('is-active');
         $('#kwota').val('');
diff --git a/src/wolnelektury/static/2022/images/checkout-bg.png b/src/wolnelektury/static/2022/images/checkout-bg.png
new file mode 100644 (file)
index 0000000..693f3d2
Binary files /dev/null and b/src/wolnelektury/static/2022/images/checkout-bg.png differ
diff --git a/src/wolnelektury/static/2022/images/checkout-img-4.jpg b/src/wolnelektury/static/2022/images/checkout-img-4.jpg
new file mode 100644 (file)
index 0000000..6cf12c0
Binary files /dev/null and b/src/wolnelektury/static/2022/images/checkout-img-4.jpg differ
index fcde582..8e50810 100644 (file)
         order: attr(data-pop);
     }
 }
+
+
+
+.toggle-input {
+    left: calc(50% - 77px/2);
+    opacity: 0;
+    position: absolute;
+    //top: 0;
+    height: 26px;
+    width: 77px;
+    z-index: 2;
+
+    &:checked {
+        z-index: 0;
+    }
+}
+
+
+.l-checkout__payments {
+    display: none;
+}
+.toggle-input{
+    &#switch-once:checked {
+        ~.l-switch__wrapper {
+            label {
+                &:nth-of-type(1) { color: #003C3C; }
+                &:nth-of-type(2) { color: #74BDC2; }
+            }
+            .toggle {
+                left: 5px;
+            }
+        }
+        ~.payments-once {
+            display: flex;
+        }
+    }
+    &#switch-monthly:checked {
+        ~.l-switch__wrapper {
+            label {
+                &:nth-of-type(1) { color: #74BDC2; }
+                &:nth-of-type(2) { color: #003C3C; }
+            }
+            .toggle {
+                left: 39px;
+            }
+        }
+        ~.payments-recurring {
+            display: flex;
+        }
+    }
+}
+
+
+
+.l-checkout__form__row {
+    .iframe {
+        margin-bottom: 16px;
+    }
+}
+
+
+
+.l-books__item__content {
+    width: 100%;
+   
+    .fragment-text {
+        max-width: 390px;
+        margin-top: 20px;
+        font-weight: 400;
+        font-size: 18px;
+        font-size: 1.125rem;
+        line-height: 150%;
+        color: #474747;
+        
+        h1, h2, h3, h4 {
+            font-size: 1em;
+        }
+    }
+}
index df14741..e54f34d 100644 (file)
@@ -19,3 +19,5 @@
 @import "breadcrumb";
 @import "content";
 @import "checkout";
+@import "pagination";
+@import "theme";
diff --git a/src/wolnelektury/static/2022/styles/layout/_pagination.scss b/src/wolnelektury/static/2022/styles/layout/_pagination.scss
new file mode 100644 (file)
index 0000000..d243670
--- /dev/null
@@ -0,0 +1,52 @@
+.l-pagination {
+  display: flex;
+  align-content: center;
+  margin: 40px auto 40px auto;
+
+  ul {
+    display: flex;
+    margin: 0;
+    padding: 0;
+    align-content: center;
+    list-style: none;
+
+    li {
+      margin: 0 5px;
+      font-weight: $regular;
+      @include font-size(18px);
+      line-height: 150%;
+      text-align: center;
+      color: #474747;
+
+      &.is-active {
+        a {
+          color: #ffffff;
+          background-color: #083F4D;
+          border-radius: 50%;
+        }
+      }
+
+      a {
+        text-align: center;
+        line-height: 35px;
+        display: block;
+        width: 35px;
+        height: 35px;
+      }
+    }
+  }
+}
+
+.l-pagination__arrow {
+  display: flex;
+  align-content: center;
+  @include font-size(10px);
+  margin: 0 20px;
+
+  .icon {
+    display: flex;
+    align-content: center;
+    line-height: 35px;
+  }
+}
+
diff --git a/src/wolnelektury/static/2022/styles/layout/_theme.scss b/src/wolnelektury/static/2022/styles/layout/_theme.scss
new file mode 100644 (file)
index 0000000..b2bb1be
--- /dev/null
@@ -0,0 +1,67 @@
+.l-theme {
+  display: flex;
+}
+
+.l-theme__col {
+  display: flex;
+  flex-direction: column;
+}
+
+.l-theme__info {
+  padding: 34px;
+  border-radius: 10px;
+  background-color: #E1F1F2;
+  margin-top: 34px;
+  max-width: 415px;
+  h3 {
+    display: flex;
+    align-content: center;
+    justify-content: space-between;
+    margin-top: 34px;
+    font-weight: $semibold;
+    @include font-size(21px);
+    line-height: 140%;
+    letter-spacing: -0.01em;
+    color: #007880;
+
+    &:first-of-type {
+      margin-top: 0;
+    }
+
+    .icon {
+      display: flex;
+      align-items: center;
+      @include font-size(14px);
+      margin-right: 0;
+      margin-left: auto;
+      cursor: pointer;
+
+      &.icon-arrow-right {
+        margin-left: 20px;
+      }
+    }
+  }
+
+  p {
+    margin-top: 10px;
+    font-weight: $regular;
+    @include font-size(18px);
+    line-height: 150%;
+    color: #474747;
+  }
+}
+
+.l-theme__info__slider {
+  width: 100%;
+  font-size: 0;
+  margin-top: 16px;
+
+  & * {
+    outline: 0 !important;
+  }
+
+  img {
+    max-width: 100%;
+    margin-right: 17px;
+  }
+}
\ No newline at end of file
diff --git a/src/wolnelektury/templates/2022/paginate.html b/src/wolnelektury/templates/2022/paginate.html
new file mode 100644 (file)
index 0000000..79ac191
--- /dev/null
@@ -0,0 +1,27 @@
+{% if is_paginated %}
+  <div class="l-pagination">
+    {% if page_obj.has_previous %}
+      <a href="?page={{ page_obj.previous_page_number }}{{ getvars }}" class="l-pagination__arrow">
+        <i class="icon icon-arrow-left"></i>
+      </a>
+    {% endif %}
+    <ul>
+      {% for page in pages %}
+        {% if page %}
+          {% if page == page_obj.number %}
+            <li class="is-active"><a>{{ page }}</a></li>
+          {% else %}
+            <li><a href="?page={{ page }}{{ getvars }}">{{ page }}</a></li>
+          {% endif %}
+        {% else %}
+          <li><a>…</a></li>
+        {% endif %}
+      {% endfor %}
+    </ul>
+    {% if page_obj.has_next %}
+      <a href="?page={{ page_obj.next_page_number }}{{ getvars }}" class="l-pagination__arrow">
+        <i class="icon icon-arrow-right"></i>
+      </a>
+    {% endif %}
+  </div>
+{% endif %}