Merge branch 'feature/packages-page-1-08-19' of gitlab.com:lilschool/site into features/course-search-16-08-19

remotes/origin/features/course-search-16-08-19
gzbender 7 years ago
commit 599db4feb8
  1. 9
      api/v1/serializers/content.py
  2. 3
      api/v1/urls.py
  3. 11
      api/v1/views.py
  4. 7
      apps/content/admin.py
  5. 38
      apps/content/migrations/0029_auto_20190730_2032.py
  6. 18
      apps/content/migrations/0030_auto_20190809_0133.py
  7. 21
      apps/content/models.py
  8. 13
      apps/notification/templates/notification/email/buy_email.html
  9. 25
      apps/payment/migrations/0038_auto_20190814_1506.py
  10. 77
      apps/payment/models.py
  11. 12
      apps/payment/templates/payment/package_payment_success.html
  12. 5
      apps/payment/templates/payment/payment_success.html
  13. 60
      apps/payment/views.py
  14. 17
      apps/school/views.py
  15. 3
      apps/user/admin.py
  16. 19
      project/templates/blocks/about.html
  17. 2
      project/templates/blocks/banner.html
  18. 2
      project/templates/blocks/banners.html
  19. 6
      project/templates/blocks/counters.html
  20. 16
      project/templates/blocks/footer.html
  21. 10
      project/templates/blocks/header.html
  22. 19
      project/templates/blocks/online_school.html
  23. 2
      project/templates/blocks/partners.html
  24. 12
      project/templates/blocks/reviews.html
  25. 32
      project/templates/blocks/students.html
  26. 72
      project/templates/blocks/teachers.html
  27. 27
      project/templates/blocks/video.html
  28. 4
      project/templates/lilcity/home.html
  29. 1
      project/templates/lilcity/index.html
  30. 2
      project/templates/lilcity/layer.html
  31. 144
      project/templates/lilcity/packages.html
  32. 3
      project/urls.py
  33. 4
      project/utils/__init__.py
  34. 46
      project/views.py
  35. 17
      web/src/img/bubble-icon.svg
  36. BIN
      web/src/img/emoji-cat.png
  37. BIN
      web/src/img/emoji-holiday.png
  38. BIN
      web/src/img/emoji-present.png
  39. BIN
      web/src/img/emoji-students.png
  40. BIN
      web/src/img/emoji-winners.png
  41. BIN
      web/src/img/emoji_present.png
  42. BIN
      web/src/img/girl-umbrela.png
  43. BIN
      web/src/img/medal.png
  44. BIN
      web/src/img/zlata.png
  45. 25
      web/src/js/modules/common.js
  46. 440
      web/src/sass/_common.sass

@ -4,7 +4,7 @@ from django.conf import settings
from apps.content.models import ( from apps.content.models import (
Banner, Content, Image, Text, ImageText, Video, Banner, Content, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject, FAQ) Gallery, GalleryImage, ImageObject, FAQ, Package)
from . import Base64ImageField from . import Base64ImageField
@ -268,3 +268,10 @@ class FAQSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = FAQ model = FAQ
fields = '__all__' fields = '__all__'
class PackageSerializer(serializers.ModelSerializer):
class Meta:
model = Package
fields = '__all__'

@ -19,7 +19,7 @@ from .views import (
SchoolScheduleViewSet, LiveLessonViewSet, SchoolScheduleViewSet, LiveLessonViewSet,
PaymentViewSet, ObjectCommentsViewSet, PaymentViewSet, ObjectCommentsViewSet,
ContestViewSet, ContestWorkViewSet, NotifiedAboutBonuses, ContestViewSet, ContestWorkViewSet, NotifiedAboutBonuses,
AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet, TagViewSet) AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet, PackageViewSet, TagViewSet)
router = DefaultRouter() router = DefaultRouter()
router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
@ -48,6 +48,7 @@ router.register(r'users', UserViewSet, base_name='users')
router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery') router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery')
router.register(r'contests', ContestViewSet, base_name='contests') router.register(r'contests', ContestViewSet, base_name='contests')
router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works') router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works')
router.register(r'packages', PackageViewSet, base_name='packages')
router.register(r'tags', TagViewSet, base_name='tags') router.register(r'tags', TagViewSet, base_name='tags')
# router.register(r'configs', ConfigViewSet, base_name='configs') # router.register(r'configs', ConfigViewSet, base_name='configs')

@ -31,7 +31,7 @@ from .serializers.content import (
VideoSerializer, VideoCreateSerializer, VideoSerializer, VideoCreateSerializer,
GallerySerializer, GallerySerializer,
GalleryImageSerializer, GalleryImageCreateSerializer, GalleryImageSerializer, GalleryImageCreateSerializer,
ImageObjectSerializer, FAQSerializer, ImageObjectSerializer, FAQSerializer, PackageSerializer,
) )
from .serializers.school import ( from .serializers.school import (
SchoolScheduleSerializer, SchoolScheduleSerializer,
@ -66,7 +66,7 @@ from apps.config.models import Config
from apps.content.models import ( from apps.content.models import (
Banner, Image, Text, ImageText, Video, Banner, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject, Gallery, GalleryImage, ImageObject,
Contest, ContestWork, FAQ) Contest, ContestWork, FAQ, Package)
from apps.payment.models import ( from apps.payment.models import (
AuthorBalance, Payment, AuthorBalance, Payment,
CoursePayment, SchoolPayment, UserBonus, CoursePayment, SchoolPayment, UserBonus,
@ -653,14 +653,13 @@ class PaymentViewSet(viewsets.ModelViewSet):
def calc_amount(self, request, pk=None): def calc_amount(self, request, pk=None):
user = request.query_params.get('user') user = request.query_params.get('user')
course = request.query_params.get('course') course = request.query_params.get('course')
weekdays = request.query_params.getlist('weekdays[]')
date_start = request.query_params.get('date_start') date_start = request.query_params.get('date_start')
is_camp = bool(request.query_params.get('is_camp')) is_camp = bool(request.query_params.get('is_camp'))
user = user and User.objects.get(pk=user) user = user and User.objects.get(pk=user)
course = course and Course.objects.get(pk=course) course = course and Course.objects.get(pk=course)
date_start = date_start and datetime.strptime(date_start, '%Y-%m-%d') date_start = date_start and datetime.strptime(date_start, '%Y-%m-%d')
return Response(Payment.calc_amount(user=user, course=course, date_start=date_start, weekdays=weekdays, return Response(Payment.calc_amount(user=user, course=course, date_start=date_start,
is_camp=is_camp)) is_camp=is_camp))
@ -775,6 +774,10 @@ class NotifiedAboutBonuses(views.APIView):
b.save() b.save()
return Response({'status': 'ok'}) return Response({'status': 'ok'})
class PackageViewSet(ExtendedModelViewSet):
queryset = Package.objects.all()
serializer_class = PackageSerializer
permission_classes = (IsAdmin,)
class TagViewSet(ExtendedModelViewSet): class TagViewSet(ExtendedModelViewSet):
queryset = Tag.objects.all() queryset = Tag.objects.all()

@ -8,7 +8,7 @@ from polymorphic.admin import (
from apps.content.models import ( from apps.content.models import (
Banner, Content, Image, Text, ImageText, Video, Banner, Content, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject, Gallery, GalleryImage, ImageObject,
Contest, ContestWork, FAQ, Contest, ContestWork, FAQ, Package,
) )
@ -99,3 +99,8 @@ class ContestWorkAdmin(admin.ModelAdmin):
@admin.register(FAQ) @admin.register(FAQ)
class FAQAdmin(admin.ModelAdmin): class FAQAdmin(admin.ModelAdmin):
base_model = FAQ base_model = FAQ
@admin.register(Package)
class PackageAdmin(admin.ModelAdmin):
base_model = Package

@ -0,0 +1,38 @@
# Generated by Django 2.0.7 on 2019-07-30 20:32
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('content', '0028_auto_20190726_0106'),
]
operations = [
migrations.CreateModel(
name='Package',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('high_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('description', models.TextField(db_index=True, default='', verbose_name='Описание')),
('duration', models.PositiveSmallIntegerField()),
('options', models.TextField(db_index=True, default='', verbose_name='Описание')),
],
options={
'ordering': ('duration',),
},
),
migrations.AlterField(
model_name='banner',
name='main_banner',
field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None),
),
migrations.AlterField(
model_name='banner',
name='pages',
field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(choices=[(1, 'Главная'), (2, 'Курсы'), (3, 'Школа'), (4, 'Пакеты')]), blank=True, default=[], size=None),
),
]

@ -0,0 +1,18 @@
# Generated by Django 2.0.7 on 2019-08-09 01:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('content', '0029_auto_20190730_2032'),
]
operations = [
migrations.AlterField(
model_name='package',
name='options',
field=models.TextField(db_index=True, default='', verbose_name='Опции'),
),
]

@ -146,11 +146,13 @@ class Banner(models.Model):
PAGE_INDEX = 1 PAGE_INDEX = 1
PAGE_COURSES = 2 PAGE_COURSES = 2
PAGE_SCHOOL = 3 PAGE_SCHOOL = 3
PAGE_PACKAGES = 4
PAGE_CHOICES = ( PAGE_CHOICES = (
(PAGE_INDEX, 'Главная'), (PAGE_INDEX, 'Главная'),
(PAGE_COURSES, 'Курсы'), (PAGE_COURSES, 'Курсы'),
(PAGE_SCHOOL, 'Школа'), (PAGE_SCHOOL, 'Школа'),
(PAGE_PACKAGES, 'Пакеты')
) )
text = models.TextField(blank=True, default='') text = models.TextField(blank=True, default='')
@ -241,3 +243,22 @@ class ContestWork(models.Model):
class FAQ(models.Model): class FAQ(models.Model):
question = models.TextField(max_length=1000,) question = models.TextField(max_length=1000,)
answer = models.TextField(max_length=1000,) answer = models.TextField(max_length=1000,)
class Package(models.Model):
price = models.DecimalField(max_digits=10, decimal_places=2,)
high_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
description = models.TextField(
'Описание', default='', db_index=True
)
duration = models.PositiveSmallIntegerField()
options = models.TextField(
'Опции', default='', db_index=True
)
class Meta:
ordering = ('duration',)
@property
def options_html(self):
return ''.join(map(lambda x: '<p>%s</p>' % x, self.options.split('\n')))

@ -3,12 +3,20 @@
{% block content %} {% block content %}
{% if product_type == 'course' %} {% if product_type == 'course' %}
<p>Курс ждет вас по ссылке <a href="https://{% setting 'MAIN_HOST' %}{{ url }}"> <p>Добрый день! Спасибо за покупку знаний в «Lil School»!</p>
<p>Где искать уроки?</p>
<p>После оплаты курс появится в вашем личном кабинете на платформе.</p>
<p><a href="https://{% setting 'MAIN_HOST' %}{{ url }}">
https://{% setting 'MAIN_HOST' %}{{ url }}</a></p> https://{% setting 'MAIN_HOST' %}{{ url }}</a></p>
<p>Все ваши покупки будут храниться там в рамках срока доступа к курсу.</p>
{% endif %} {% endif %}
{% if product_type == 'school' %} {% if product_type == 'school' %}
<p>Школа ждет вас по ссылке <a href="https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}"> <p>Добрый день! Спасибо за покупку знаний в «Lil School»!</p>
<p>Где искать уроки?</p>
<p>После оплаты уроки появятся в вашем личном кабинете на платформе.</p>
<p><a href="https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}">
https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}</a></p> https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}</a></p>
<p>В онлайн-школе урок хранится неделю. Ровно до следующего урока.</p>
{% endif %} {% endif %}
{% if product_type == 'drawing_camp' %} {% if product_type == 'drawing_camp' %}
{% if date_start.month == 7 and date_start.day == 1 and date_end.day == 31 %} {% if date_start.month == 7 and date_start.day == 1 and date_end.day == 31 %}
@ -72,7 +80,6 @@
https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}</a></p> https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}</a></p>
{% endif %} {% endif %}
{% endif %} {% endif %}
<p>Так же вы можете найти ссылку в личном кабинете в разделе «Мои покупки».</p>
<p>Занимайтесь с удовольствием!</p> <p>Занимайтесь с удовольствием!</p>

@ -0,0 +1,25 @@
# Generated by Django 2.0.7 on 2019-08-14 15:06
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('content', '0030_auto_20190809_0133'),
('payment', '0037_add_paid_one_more_bonuses'),
]
operations = [
migrations.AddField(
model_name='schoolpayment',
name='package',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='content.Package'),
),
migrations.AlterField(
model_name='payment',
name='bonus',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_payments', to='payment.UserBonus'),
),
]

@ -16,12 +16,14 @@ from django.core.validators import RegexValidator
from django.utils.timezone import now from django.utils.timezone import now
from django.conf import settings from django.conf import settings
from apps.content.models import Package
from project.utils import weekdays_in_date_range from project.utils import weekdays_in_date_range
from apps.course.models import Course from apps.course.models import Course
from apps.config.models import Config from apps.config.models import Config
from apps.school.models import SchoolSchedule from apps.school.models import SchoolSchedule
from apps.notification.utils import send_email from apps.notification.utils import send_email
from project.utils import dates_overlap
config = Config.load() config = Config.load()
@ -126,11 +128,11 @@ class Payment(PolymorphicModel):
ordering = ('created_at',) ordering = ('created_at',)
@classmethod @classmethod
def ajust_date_bounds(cls, date_start=None, date_end=None, is_camp=False): def adjust_date_bounds(cls, date_start=None, date_end=None, is_camp=False):
school_start = date(now().year, 9, 1) school_start = date((date_start or date_end).year, 9, 1)
school_end = date(now().year, 5, 31) school_end = date((date_end or date_start).year, 5, 31)
camp_start = date(now().year, 6, 1) camp_start = date((date_start or date_end).year, 6, 1)
camp_end = date(now().year, 8, 31) camp_end = date((date_end or date_start).year, 8, 31)
if date_start: if date_start:
if is_camp: if is_camp:
@ -151,24 +153,32 @@ class Payment(PolymorphicModel):
else: else:
return date_start or date_end return date_start or date_end
@classmethod
def date_add(cls, date_start, days=0, months=0, is_camp=False):
date_end = arrow.get(date_start + timedelta(days=days), settings.TIME_ZONE).shift(
months=months).date() - timedelta(1)
if months == 1:
if is_camp or (date_start.month == 2 and date_start.day >= 28) or (
date_start.day == 31 and date_end.day <= 30) \
or (date_start.month == 1 and date_start.day >= 29 and date_end.day == 28):
date_end = date_start.replace(day=1, month=date_start.month + 1) - timedelta(1)
return date_end
@classmethod @classmethod
def get_date_range(cls, date_start=None, days=0, months=0, is_camp=False): def get_date_range(cls, date_start=None, days=0, months=0, is_camp=False):
date_start = date_start or now().date() date_start = date_start or now().date()
if isinstance(date_start, datetime): if isinstance(date_start, datetime):
date_start = date_start.date() date_start = date_start.date()
date_start = cls.ajust_date_bounds(date_start=date_start, is_camp=is_camp) date_start = cls.adjust_date_bounds(date_start=date_start, is_camp=is_camp)
if is_camp and date_start.month == 6 and date_start.day > 16: if is_camp and date_start.month == 6 and date_start.day > 16:
date_start = date_start.replace(month=7, day=1) date_start = date_start.replace(month=7, day=1)
date_end = arrow.get(date_start + timedelta(days=days), settings.TIME_ZONE).shift(months=months).date() - timedelta(1) date_end = cls.date_add(date_start, days, months, is_camp)
if months == 1: if is_camp:
if is_camp or (date_start.month == 2 and date_start.day >= 28) or (date_start.day == 31 and date_end.day <= 30) \ date_end = cls.adjust_date_bounds(date_end, is_camp=is_camp)
or (date_start.month == 1 and date_start.day >= 29 and date_end.day == 28):
date_end = date_start.replace(day=1, month=date_start.month + 1) - timedelta(1)
date_end = cls.ajust_date_bounds(date_end=date_end, is_camp=is_camp)
return [date_start, date_end] return [date_start, date_end]
@classmethod @classmethod
def calc_amount(cls, payment=None, user=None, course=None, date_start=None, weekdays=None, is_camp=False): def calc_amount(cls, package=None, payment=None, user=None, course=None, date_start=None, weekdays=None, is_camp=False):
price = 0 price = 0
discount = 0 discount = 0
referral_bonus = 0 referral_bonus = 0
@ -178,14 +188,14 @@ class Payment(PolymorphicModel):
user = payment.user user = payment.user
if isinstance(payment, SchoolPayment): if isinstance(payment, SchoolPayment):
user = payment.user user = payment.user
weekdays = payment.weekdays
date_start = payment.date_start date_start = payment.date_start
package=payment.package
if isinstance(payment, DrawingCampPayment): if isinstance(payment, DrawingCampPayment):
user = payment.user user = payment.user
date_start = payment.date_start date_start = payment.date_start
if issubclass(cls, DrawingCampPayment): if issubclass(cls, DrawingCampPayment):
is_camp = True is_camp = True
date_start, date_end = Payment.get_date_range(date_start, months=1, is_camp=is_camp) date_start, date_end = Payment.get_date_range(date_start, months=package.duration if package else 1, is_camp=is_camp)
if hasattr(user, 'referral') and not user.referral.payment: if hasattr(user, 'referral') and not user.referral.payment:
referral_bonus = user.referral.bonus referral_bonus = user.referral.bonus
referrer_bonus = user.referral.referrer_bonus referrer_bonus = user.referral.referrer_bonus
@ -213,40 +223,22 @@ class Payment(PolymorphicModel):
date_end__gte=date_start, date_end__gte=date_start,
status__in=Payment.PW_PAID_STATUSES, status__in=Payment.PW_PAID_STATUSES,
) )
school_schedules_purchased = school_payments.annotate(
joined_weekdays=Func(F('weekdays'), function='unnest', )
).values_list('joined_weekdays', flat=True).distinct()
weekdays = list(set(map(int, weekdays)) - set(school_schedules_purchased))
prev_school_payment = school_payments.filter(add_days=False).last() prev_school_payment = school_payments.filter(add_days=False).last()
add_days = bool(prev_school_payment) if prev_school_payment:
else: date_start, date_end = Payment.get_date_range(prev_school_payment.date_end + timedelta(1),
add_days = False months=package.duration, is_camp=False)
school_schedules = SchoolSchedule.objects.filter( school_schedules = SchoolSchedule.objects.filter(is_camp=False).exclude(title='')
weekday__in=weekdays, weekdays = list(school_schedules.values_list('weekday', flat=True))
is_camp=False,
)
if add_days:
date_end = prev_school_payment.date_end
weekdays_count = weekdays_in_date_range(date_start, prev_school_payment.date_end)
all_weekdays_count = weekdays_in_date_range(prev_school_payment.date_start, prev_school_payment.date_end)
for ss in school_schedules:
price += ss.month_price // all_weekdays_count.get(ss.weekday, 0) * weekdays_count.get(
ss.weekday, 0)
else:
# FIXME после мая 2019 убрать? # FIXME после мая 2019 убрать?
# Если хотят купить школу в мае, то оплатить ее можно только до 31 мая, потом школа закроется # Если хотят купить школу в мае, то оплатить ее можно только до 31 мая, потом школа закроется
if date_start.month == 5: if date_start.month == 5:
weekdays_count = weekdays_in_date_range(date_start, date_end) weekdays_count = weekdays_in_date_range(date_start, date_end)
weekdays_count = sum(weekdays_count[wd] for wd in weekdays)
all_weekdays_count = weekdays_in_date_range(date_start.replace(day=1), date_end) all_weekdays_count = weekdays_in_date_range(date_start.replace(day=1), date_end)
for ss in school_schedules: all_weekdays_count = sum(all_weekdays_count[wd] for wd in weekdays)
price += ss.month_price // all_weekdays_count.get(ss.weekday, 0) * weekdays_count.get( price = package.price // all_weekdays_count * weekdays_count
ss.weekday, 0)
else: else:
price = school_schedules.aggregate( price = package.price
models.Sum('month_price'),
).get('month_price__sum', 0)
if not (payment and payment.id) and price >= config.SERVICE_DISCOUNT_MIN_AMOUNT:
discount = config.SERVICE_DISCOUNT
amount = price - discount amount = price - discount
referral_bonus = round(amount * referral_bonus / 100) referral_bonus = round(amount * referral_bonus / 100)
referrer_bonus = round(amount * referrer_bonus / 100) referrer_bonus = round(amount * referrer_bonus / 100)
@ -337,6 +329,7 @@ class CoursePayment(Payment):
class SchoolPayment(Payment): class SchoolPayment(Payment):
weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели')
add_days = models.BooleanField('Докупленные дни', default=False) add_days = models.BooleanField('Докупленные дни', default=False)
package = models.ForeignKey(Package, null=True, blank=True, on_delete=models.SET_NULL)
date_start = models.DateField('Дата начала подписки', null=True, blank=True) date_start = models.DateField('Дата начала подписки', null=True, blank=True)
date_end = models.DateField('Дата окончания подписки', null=True, blank=True) date_end = models.DateField('Дата окончания подписки', null=True, blank=True)

@ -0,0 +1,12 @@
{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %}
<div class="section">
<div class="section__center center center_xs">
<div class="done">
<div class="done__title title">Вы успешно приобрели подписку с {{ package.date_start }} по {{ package.date_end }}!</div>
<div class="done__foot">
<a class="done__btn btn btn_md btn_stroke" href="{% url 'index' %}">НА ГЛАВНУЮ</a>
</div>
</div>
</div>
</div>
{% endblock content %}

@ -1,9 +1,10 @@
{% extends "templates/lilcity/index.html" %} {% load static %} {% block content %} {% extends "templates/lilcity/index.html" %} {% load static %}{% load plural %}
{% block content %}
<div class="section"> <div class="section">
<div class="section__center center center_xs"> <div class="section__center center center_xs">
<div class="done"> <div class="done">
{% if school %} {% if school %}
<div class="done__title title">Вы успешно приобрели доступ к урокам онлайн-школы!</div> <div class="done__title title">Вы успешно приобрели доступ на {{ duration|rupluralize:"месяц,месяца,месяцев" }}!</div>
<div class="done__foot"> <div class="done__foot">
<a class="done__btn btn btn_md btn_stroke" href="{% url 'school:school' %}">ПЕРЕЙТИ К ШКОЛЕ</a> <a class="done__btn btn btn_md btn_stroke" href="{% url 'school:school' %}">ПЕРЕЙТИ К ШКОЛЕ</a>
</div> </div>

@ -20,6 +20,7 @@ from django.utils.timezone import now
from paymentwall import Pingback, Product, Widget from paymentwall import Pingback, Product, Widget
from apps.content.models import Package
from apps.course.models import Course from apps.course.models import Course
from apps.payment.tasks import transaction_to_mixpanel, product_payment_to_mixpanel, transaction_to_roistat from apps.payment.tasks import transaction_to_mixpanel, product_payment_to_mixpanel, transaction_to_roistat
from apps.notification.utils import send_email from apps.notification.utils import send_email
@ -48,7 +49,12 @@ class SchoolBuySuccessView(TemplateView):
template_name = 'payment/payment_success.html' template_name = 'payment/payment_success.html'
def get(self, request, pk=None, is_camp=False, *args, **kwargs): def get(self, request, pk=None, is_camp=False, *args, **kwargs):
return self.render_to_response(context={'camp': True} if is_camp else {'school': True}) context = {
'duration': request.GET.get('duration'),
'camp': is_camp,
'school': not is_camp
}
return self.render_to_response(context=context)
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
@ -116,55 +122,22 @@ class SchoolBuyView(TemplateView):
template_name = 'payment/paymentwall_widget.html' template_name = 'payment/paymentwall_widget.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
raise Http404() # FIXME
host = urlsplit(self.request.META.get('HTTP_REFERER')) host = urlsplit(self.request.META.get('HTTP_REFERER'))
host = str(host[0]) + '://' + str(host[1]) host = str(host[0]) + '://' + str(host[1])
weekdays = set(request.GET.getlist('weekdays', []))
use_bonuses = request.GET.get('use_bonuses') use_bonuses = request.GET.get('use_bonuses')
roistat_visit = request.COOKIES.get('roistat_visit', None) roistat_visit = request.COOKIES.get('roistat_visit', None)
date_start = request.GET.get('date_start') date_start = request.GET.get('date_start')
duration = request.GET.get('duration')
package = get_object_or_404(Package, duration=duration)
date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date()
date_start, date_end = Payment.get_date_range(date_start, months=1) amount_data = SchoolPayment.calc_amount(package=package, user=request.user, date_start=date_start)
if not weekdays:
messages.error(request, 'Выберите несколько дней недели.')
return redirect('school:school')
try:
weekdays = [int(weekday) for weekday in weekdays]
except ValueError:
messages.error(request, 'Ошибка выбора дней недели.')
return redirect('school:school')
prev_school_payment = SchoolPayment.objects.filter(
user=request.user,
date_start__lte=date_start,
date_end__gte=date_start,
add_days=False,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
).last()
add_days = bool(prev_school_payment)
if add_days:
school_payment = SchoolPayment.objects.create( school_payment = SchoolPayment.objects.create(
user=request.user, user=request.user,
weekdays=weekdays, weekdays=amount_data.get('weekdays'),
date_start=date_start,
date_end=prev_school_payment.date_end,
add_days=True,
roistat_visit=roistat_visit,
)
# Если произойдет ошибка и оплату бонусами повторят еще раз на те же дни, то вернет ошибку
if school_payment.amount <= 0:
messages.error(request, 'Выбранные дни отсутствуют в оставшемся периоде подписки')
return redirect(reverse_lazy('school:school'))
else:
school_payment = SchoolPayment.objects.create(
user=request.user,
weekdays=weekdays,
roistat_visit=roistat_visit, roistat_visit=roistat_visit,
date_start=date_start, date_start=amount_data.get('date_start'),
date_end=date_end, date_end=amount_data.get('date_end'),
package=package,
) )
if use_bonuses and request.user.bonus: if use_bonuses and request.user.bonus:
if request.user.bonus >= school_payment.amount: if request.user.bonus >= school_payment.amount:
@ -183,7 +156,7 @@ class SchoolBuyView(TemplateView):
f'school_{school_payment.id}', f'school_{school_payment.id}',
school_payment.amount, school_payment.amount,
'RUB', 'RUB',
'Школа', 'Подписка',
) )
widget = Widget( widget = Widget(
str(request.user.id), str(request.user.id),
@ -195,7 +168,7 @@ class SchoolBuyView(TemplateView):
'evaluation': 1, 'evaluation': 1,
'demo': 1, 'demo': 1,
'test_mode': 1, 'test_mode': 1,
'success_url': host + str(reverse_lazy('payment-success')), 'success_url': host + str(reverse_lazy('payment-success')) + '?duration=%s' % duration,
'failure_url': host + str(reverse_lazy('payment-error')), 'failure_url': host + str(reverse_lazy('payment-error')),
} }
) )
@ -362,6 +335,7 @@ class PaymentwallCallbackView(View):
'created_at': payment.created_at, 'created_at': payment.created_at,
'update_at': payment.update_at, 'update_at': payment.update_at,
} }
payment.save() payment.save()
product_payment_to_mixpanel.delay( product_payment_to_mixpanel.delay(

@ -70,7 +70,7 @@ class DrawingCampLessonsView(ListView):
def get_queryset(self): def get_queryset(self):
date_start = (now() - timedelta(days=7)).date() date_start = (now() - timedelta(days=7)).date()
date_start, date_end = DrawingCampPayment.ajust_date_bounds(date_start, date_start + timedelta(days=23), is_camp=True) date_start, date_end = DrawingCampPayment.adjust_date_bounds(date_start, date_start + timedelta(days=23), is_camp=True)
date_range = Q( date_range = Q(
date__range=[date_start, date_end] date__range=[date_start, date_end]
) )
@ -106,15 +106,15 @@ class LiveLessonsDetailView(DetailView):
is_purchased = DrawingCampPayment.objects.all() is_purchased = DrawingCampPayment.objects.all()
else: else:
is_purchased = SchoolPayment.objects.filter(weekdays__contains=[self.object.date.weekday() + 1],) is_purchased = SchoolPayment.objects.filter(weekdays__contains=[self.object.date.weekday() + 1],)
is_purchased = is_purchased.filter( is_purchased = is_purchased.paid().filter(
user=request.user, user=request.user,
date_start__lte=now(), date_start__lte=now(),
date_end__gte=now() - timedelta(days=7), date_end__gte=now() - timedelta(days=7),
status__in=[ ).exists() or is_purchased.paid().filter(
Pingback.PINGBACK_TYPE_REGULAR, user=request.user,
Pingback.PINGBACK_TYPE_GOODWILL, date_start__lte=now(),
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, date_end__gte=now() - timedelta(days=30),
], package__duration__lte=9,
).exists() ).exists()
if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]: if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]:
raise Http404 raise Http404
@ -221,6 +221,9 @@ class SchoolView(TemplateView):
# берем все подписки, которые были в периоде # берем все подписки, которые были в периоде
for sp in prev_school_payments: for sp in prev_school_payments:
# берем все уроки в оплаченном промежутке # берем все уроки в оплаченном промежутке
if sp.package and sp.package.duration >= 9:
date_range = [max(sp.date_start, date_now - timedelta(30)), min(sp.date_end, prev_range[1])]
else:
date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])]
prev_live_lessons += list(LiveLesson.objects.filter( prev_live_lessons += list(LiveLesson.objects.filter(
date__range=date_range, date__range=date_range,

@ -12,7 +12,8 @@ User = get_user_model()
class UserAdmin(BaseUserAdmin): class UserAdmin(BaseUserAdmin):
fieldsets = ( fieldsets = (
(None, {'fields': ('username', 'password')}), (None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'gender', 'about', 'photo')}), (_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'gender', 'about', 'photo',)}),
('Teacher', {'fields': ('show_in_mainpage', 'trial_lesson', 'instagram_hashtag',)}),
('Facebook Auth data', {'fields': ('fb_id', 'fb_data', 'is_email_proved')}), ('Facebook Auth data', {'fields': ('fb_id', 'fb_data', 'is_email_proved')}),
(_('Permissions'), {'fields': ('role', 'is_active', 'is_staff', 'is_superuser', (_('Permissions'), {'fields': ('role', 'is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions', 'show_in_mainpage')}), 'groups', 'user_permissions', 'show_in_mainpage')}),

@ -1,12 +1,23 @@
{% load static %}
<div class="anchor" id="about"></div> <div class="anchor" id="about"></div>
<div class="section section_school"> <div class="section section_main section_flex section_about">
<div class="section__center center"> <div class="section__center center">
<div class="text text_lg"> <div class="section__column section__column_img">
</div>
<div class="section__column section__column_text">
<div class="title">Для кого?<img class="emoji" src="{% static 'img/emoji-students.png' %}" /></div>
<div class="text text_left">
<p>Вы житель мегаполиса и&nbsp;у&nbsp;вас нет времени дополнительно развивать своего ребенка? <p>Вы житель мегаполиса и&nbsp;у&nbsp;вас нет времени дополнительно развивать своего ребенка?
Или&nbsp;вы&nbsp;живете в&nbsp;маленьком городе, Или&nbsp;вы&nbsp;живете в&nbsp;маленьком городе,
где&nbsp;нет&nbsp;качественных школ и&nbsp;секций для&nbsp;детей?</p> где&nbsp;нет&nbsp;качественных школ и&nbsp;секций для&nbsp;детей?</p>
<p><b>Lil School</b>&nbsp;это решение для&nbsp;тех&nbsp;родителей, кто&nbsp;стремится дать лучшее своему ребенку. <p><b>Lil-School</b>&nbsp;это решение для&nbsp;тех&nbsp;родителей, кто&nbsp;стремится дать лучшее своему ребенку.
Учитесь не&nbsp;выходя из&nbsp;дома!</p> Учитесь, не&nbsp;выходя из&nbsp;дома!</p>
</div>
<div class="section__buttons">
<a class="btn btn_width-auto" style="width: auto;"
href="{% url 'packages' %}">Узнать стоимость</a>
<a href="{% url 'gift-certificates' %}" class="btn btn_gray">Подарить другу</a>
</div>
</div> </div>
</div> </div>
</div> </div>

@ -1,5 +1,5 @@
<div class="banner" <div class="banner"
data-banner="{{banner.id}}" style="display: none; data-banner="{{banner.id}}" style="
background: {{ banner.color|default:'white' }}; background: {{ banner.color|default:'white' }};
{% if banner.color2 %} {% if banner.color2 %}
background: -moz-linear-gradient(-45deg, {{ banner.color }} 0%, {{ banner.color2 }} 100%); background: -moz-linear-gradient(-45deg, {{ banner.color }} 0%, {{ banner.color2 }} 100%);

@ -16,5 +16,7 @@
<div class="swiper-pagination" slot="pagination"></div> <div class="swiper-pagination" slot="pagination"></div>
</swiper> </swiper>
{% else %} {% else %}
<div class="banners">
{% include 'templates/blocks/banner.html' with banner=banners.0 %} {% include 'templates/blocks/banner.html' with banner=banners.0 %}
</div>
{% endif %} {% endif %}

@ -1,11 +1,10 @@
{% load static %} {% load static %}
{% load ruplural from plural %} {% load ruplural from plural %}
<div class="section section_school"> <div class="section section_main section_gray section_counters">
<div class="section__center center"> <div class="section__center center">
<div class="text text_only_curve"> <div class="text text_only_curve">
<img class="text__curve text__curve_five" src="{% static 'img/curve-2.svg' %}" width="210"> <img class="text__curve text__curve_six" src="{% static 'img/curve-2.svg' %}" width="210">
<div class="title">Lil School в цифрах</div>
</div> </div>
<div class="school school_main"> <div class="school school_main">
<div class="school__col"> <div class="school__col">
@ -32,6 +31,5 @@
<div class="school__text">со&nbsp;всего мира со&nbsp;счастливыми учениками Lil&nbsp;School</div> <div class="school__text">со&nbsp;всего мира со&nbsp;счастливыми учениками Lil&nbsp;School</div>
</div> </div>
</div> </div>
<div style="margin: 50px 0; text-align: center;"><a class="btn" href="/faq">Часто задаваемые вопросы</a></div>
</div> </div>
</div> </div>

@ -1,7 +1,17 @@
{% load static %} {% load static %}
<footer class="footer"> <footer class="footer">
<div class="footer__center center"> <div class="footer__center center">
<div class="footer__row footer__row_first"> <div class="footer__row footer__row_subscr mobile-show">
<div class="footer__col footer__col_md">
<div>Подписаться на&nbsp;самую интересную рассылку на&nbsp;планете</div>
<form class="subscribe" method="post" action="{% url 'subscribe' %}">
{% csrf_token %}
<input class="subscribe__input" name="email" placeholder="Email">
<button class="subscribe__btn btn btn_light">ПОДПИСАТЬСЯ</button>
</form>
</div>
</div>
<div class="footer__row">
<div class="footer__col footer__col_md"> <div class="footer__col footer__col_md">
<a class="footer__logo logo" href="/"></a> <a class="footer__logo logo" href="/"></a>
<div class="footer__content">Lil School – первая образовательная онлайн-платформа креативного мышления <div class="footer__content">Lil School – первая образовательная онлайн-платформа креативного мышления
@ -57,15 +67,17 @@
</nav> </nav>
</div> </div>
</div> </div>
<div class="footer__row footer__row_second"> <div class="footer__row footer__row_subscr">
<div class="footer__col footer__col_md mobile-hide"></div> <div class="footer__col footer__col_md mobile-hide"></div>
<div class="footer__col footer__col_md"> <div class="footer__col footer__col_md">
<div class="mobile-hide">
<div>Подписаться на&nbsp;самую интересную рассылку на&nbsp;планете</div> <div>Подписаться на&nbsp;самую интересную рассылку на&nbsp;планете</div>
<form class="subscribe" method="post" action="{% url 'subscribe' %}"> <form class="subscribe" method="post" action="{% url 'subscribe' %}">
{% csrf_token %} {% csrf_token %}
<input class="subscribe__input" name="email" placeholder="Email"> <input class="subscribe__input" name="email" placeholder="Email">
<button class="subscribe__btn btn btn_light">ПОДПИСАТЬСЯ</button> <button class="subscribe__btn btn btn_light">ПОДПИСАТЬСЯ</button>
</form> </form>
</div>
<div class="footer__copyright"> <div class="footer__copyright">
Все права защищены ©&nbsp;Lil&nbsp;City,&nbsp;UAB. Все&nbsp;материалы принадлежат компании Lil&nbsp;City,&nbsp;UAB.<br> Все права защищены ©&nbsp;Lil&nbsp;City,&nbsp;UAB. Все&nbsp;материалы принадлежат компании Lil&nbsp;City,&nbsp;UAB.<br>
Никакая из&nbsp;частей этого сайта, текстов или&nbsp;изображений, не&nbsp;может быть&nbsp;скопирована, использована или&nbsp;передана Никакая из&nbsp;частей этого сайта, текстов или&nbsp;изображений, не&nbsp;может быть&nbsp;скопирована, использована или&nbsp;передана

@ -25,6 +25,11 @@
</form> </form>
</div> </div>
<nav class="header__nav"> <nav class="header__nav">
<div class="header__group mobile-show">
<a class="header__section {% active_link 'index' %}" href="{% url 'index' %}">
ГЛАВНАЯ
</a>
</div>
<!-- <div class="header__group"> <!-- <div class="header__group">
<a class="header__section {% active_link 'school:school' %}" href="{% url 'school:school' %}"> <a class="header__section {% active_link 'school:school' %}" href="{% url 'school:school' %}">
ОНЛАЙН-ШКОЛА {% if online or livelesson.is_online %} ОНЛАЙН-ШКОЛА {% if online or livelesson.is_online %}
@ -51,6 +56,11 @@
{% category_menu_items category %} {% category_menu_items category %}
</div> </div>
</div> </div>
<div class="header__group">
<a class="header__section {% active_link 'packages' %}" href="{% url 'packages' %}">
ЦЕНЫ
</a>
</div>
<div class="header__group"> <div class="header__group">
<a class="header__section" href="https://blog.lil.school">БЛОГ</a> <a class="header__section" href="https://blog.lil.school">БЛОГ</a>
</div> </div>

@ -1,21 +1,14 @@
<div class="section section_school"> {% load static %}
<div class="section section_main section_school">
<div class="section__center center"> <div class="section__center center">
<div class="title title_center">Процесс</div> <div class="title title_center">Процесс</div>
<div class="text"> <div class="school school_main school_three-col">
Онлайн-образование &mdash; это очень удобно! Можете учиться в&nbsp;пижаме, без&nbsp;макияжа
и&nbsp;с&nbsp;огурцами на&nbsp;лице!)
</div>
<div class="school school_main">
<div class="school__col"> <div class="school__col">
<div class="school__preview">Видеоуроки</div> <div class="school__preview">Видеоуроки</div>
<div class="school__text">Каждый день!</div> <div class="school__text">Каждый день!</div>
</div> </div>
<div class="school__col"> <div class="school__col">
<div class="school__preview">В 17:00</div> <div class="school__preview">5 дисциплин</div>
<div class="school__text">По московскому времени</div>
</div>
<div class="school__col">
<div class="school__preview">7 дисциплин</div>
<div class="school__text">В разных техниках</div> <div class="school__text">В разных техниках</div>
</div> </div>
<div class="school__col"> <div class="school__col">
@ -23,6 +16,8 @@
<div class="school__text">Хранится 7 дней</div> <div class="school__text">Хранится 7 дней</div>
</div> </div>
</div> </div>
<div class="letsgo"></div> <div style="margin: 50px 0px 15px; text-align: center;">
<a class="btn btn_white" href="/faq">Часто задаваемые вопросы</a>
</div>
</div> </div>
</div> </div>

@ -1,5 +1,5 @@
{% load static %} {% load static %}
<div class="section" id="partners"> <div class="section section_main section_partners" id="partners">
<div class="section__center center"> <div class="section__center center">
<a name="partners"> <a name="partners">
<div class="title title_center">Наши партнеры</div> <div class="title title_center">Наши партнеры</div>

@ -1,14 +1,18 @@
{% load static %} {% load static %}
<div class="section reviews-section"> <div class="section section_main reviews-section">
<div class="reviews-section__center section__center center center_md"> <div class="reviews-section__center section__center center center_md">
<div class="reviews-section__title"> <div class="reviews-section__title">
<a id="reviews" name="reviews"> <a id="reviews" name="reviews">
<div class="title title_left">Отзывы о Lil School</div> <div class="title">Отзывы о Lil School<img class="emoji" src="{% static 'img/emoji-holiday.png' %}" /></div>
</a> </a>
<div class="text">Тёплых отзывов настолько много, что потребуется несколько суток, чтобы их просмотреть <div class="text text_left">
<p>Тёплых отзывов настолько много, что потребуется несколько суток, чтобы их просмотреть
и несколько месяцев чтобы прочитать.<br> и несколько месяцев чтобы прочитать.<br>
P.S.: Но мы читаем их все!) P.S.: Но мы читаем их все!)</p>
</div> </div>
{% if not request.user.is_authenticated and not request.user_agent.is_mobile %}
<a class="btn btn_pink-blue" href="#" data-popup=".js-popup-auth">Присоединиться к Lil School</a>
{% endif %}
</div> </div>
<div class="reviews-section__reviews reviews" data-review-images="{{ review_images|join:',' }}"> <div class="reviews-section__reviews reviews" data-review-images="{{ review_images|join:',' }}">
<div class="reviews__wrap"> <div class="reviews__wrap">

@ -0,0 +1,32 @@
{% load static %}
<div class="anchor" id="students"></div>
<div class="section section_main section_flex section_students">
<div class="section__center center">
<div class="section__column section__column_text">
<div class="title">Наши ученики – многократные призеры международных конкурсов!
<img class="emoji" src="{% static 'img/emoji-winners.png' %}" /></div>
</div>
<div class="section__column section__column_text">
<div class="text text_left">
<p>Креативное мышление необходимо всем: дизайнерам, математикам, инженерам, предпринимателям и врачам.</p>
</div>
</div>
</div>
<div class="section__center center">
<div class="section__column section__column_img">
</div>
<div class="section__column section__column_text">
<div class="section__quote">
<div class="section__quote-text">
Лил Скул для меня это место, где Солнце может быть синего цвета.
</div>
<div class="section__quote-name">Злата Пыльцина, 7 лет. Город Волгоград.</div>
</div>
<div class="section__buttons">
<a class="btn js-video-modal" style="width: auto;"
data-video-url="https://www.youtube.com/watch?v=QrlR5sL_eGI"
href="#">Видео отзыв</a>
</div>
</div>
</div>
</div>

@ -1,33 +1,34 @@
{% load static %} {% load static %}
<div id="teachers" class="anchor"></div> <div id="teachers" class="anchor"></div>
<div class="section"> <div class="section section_main section_flex">
<div class="section__center center center_md"> <div class="section__center center">
<div class="title title_center">Преподаватели</div> <div class="section__column section__column_text">
<div class="text"> <div class="title">Преподаватели</div>
<p>Преподаватели Lil School имеют большой опыт, поэтому с первых минут детям будет интересно с нами.</p> <div class="text text_left text_only_curve mobile-show"><img src="/static/img/curve-3.svg" class="text__curve" style="
<img class="text__curve text__curve_three" src="{% static 'img/curve-3.svg' %}"> right: 0px;
top: -30px;
"></div>
<div class="text text_left">
<p>Преподаватели Lil School имеют большой опыт, поэтому с первых минут детям будет интересно.</p>
</div> </div>
</div>
<div class="section__column mobile-hide" style="padding-left: 100px;">
<div class="text text_left text_only_curve">
<img class="text__curve" src="{% static 'img/curve-3.svg' %}">
</div>
</div>
</div>
<div class="section__center center">
<div class="teachers"> <div class="teachers">
{% for teacher in teachers %} {% for teacher in teachers %}
{% cycle '<div class="teachers__row">' '' %}
<div class="teachers__item"> <div class="teachers__item">
<div class="teachers__left-column">
<div class="teachers__ava ava"> <div class="teachers__ava ava">
{% if teacher.photo %} {% if teacher.photo %}
<img class="ava__pic" src="{{ teacher.photo.url }}"> {% else %} <img class="ava__pic" src="{{ teacher.photo.url }}"> {% else %}
<img class="ava__pic" src="{% static 'img/user_default.jpg' %}"> {% endif %} <img class="ava__pic" src="{% static 'img/user_default.jpg' %}"> {% endif %}
</div> </div>
<div class="teachers__wrap">
<div class="teachers__title">
<div class="teachers__title-name">
<a href="{{ teacher.url }}">{{ teacher.get_full_name }}</a>{% if teacher.instagram_hashtag %},
<a href='https://www.instagram.com/explore/tags/{{ teacher.instagram_hashtag }}/' target="_blank">
{{ teacher.instagram_hashtag }}
</a>
{% endif %}
</div>
{% if teacher.trial_lesson %}
<a data-video-url="{{ teacher.trial_lesson }}" data-trial-lesson="1" href="#" class="btn btn_light js-video-modal">ПРОБНЫЙ УРОК</a>
{% endif %}
</div>
<div class="teachers__social"> <div class="teachers__social">
{% if teacher.facebook %} {% if teacher.facebook %}
<a class="social__item" href="{{ teacher.facebook }}" target="_blank"> <a class="social__item" href="{{ teacher.facebook }}" target="_blank">
@ -61,15 +62,46 @@
</a> </a>
{% endif %} {% endif %}
</div> </div>
</div>
<div class="teachers__right-column">
<div class="teachers__title">
<a href="{{ teacher.url }}" style="color: black;">{{ teacher.get_full_name }}</a>{% if teacher.instagram_hashtag %}<br>
<a href='https://www.instagram.com/explore/tags/{{ teacher.instagram_hashtag }}/' target="_blank">
#{{ teacher.instagram_hashtag }}
</a>
{% endif %}
</div>
{% if teacher.about %} {% if teacher.about %}
<div class="teachers__content"> <div class="teachers__content">
{{ teacher.about }} {{ teacher.about }}
</div> </div>
{% endif %} {% endif %}
{% if teacher.trial_lesson %}
<a data-video-url="{{ teacher.trial_lesson }}" data-trial-lesson="1" href="#" class="btn btn_light js-video-modal">ПРОБНЫЙ УРОК</a>
{% endif %}
</div>
</div>
{% cycle '' '</div>' %}
{% if forloop.last and not forloop.counter|divisibleby:'2' %}
<div class="teachers__item">
<div class="teachers__left-column">
<div class="teachers__ava ava">
<img class="ava__pic" src="{% static 'img/user_default.jpg' %}" syle="margin-top: 10px;">
</div> </div>
</div> </div>
<div class="teachers__right-column">
<div class="teachers__title">
Хотите в команду<br>Lil School?
</div>
<div class="teachers__content">
Любите развивать детей, развиваться сами и хотите зарабатывать на любимом деле?<br><br>
<a href="{% url 'author_request' %}">Оставьте заявку</a>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
<div class="text text_mb0">Если хотите к нам в команду, то <a href="{% url 'author_request' %}">отправьте</a> нам заявку</div>
</div> </div>
</div> </div>

@ -1,10 +1,25 @@
<div class="section section_video"> {% load static %}
<div class="section__center center center_sm" style="text-align: center;"> <div class="section section_main section_flex section_video">
<div class="title">Пробный урок</div> <div class="section__center center">
<div class="section__column section__column_text">
<div class="title">Попробуйте бесплатно<img class="emoji" src="{% static 'img/emoji-cat.png' %}" /></div>
<div class="text text_left">
<p>Тысячи видео-уроков на разные темы для развития творческого мышления уже ждут вас. Учитесь, не выходя из дома!</p>
</div>
<div class="section__buttons mobile-hide">
<a href="#" class="btn btn_white js-video-modal" style="width: auto;"
data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1">Смотреть бесплатный урок
<img class="emoji" src="{% static 'img/emoji-present.png' %}" /></a>
</div>
</div>
<div class="section__column section__column_img">
<img class="main-video-preview js-video-modal" data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1" <img class="main-video-preview js-video-modal" data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1"
src="{{ config.MAIN_PAGE_VIDEO_PREVIEW_IMG.url }}"/> src="{{ config.MAIN_PAGE_VIDEO_PREVIEW_IMG.url }}"/>
<a href="#" class="btn js-video-modal btn_stroke-black" style="margin: 20px;" <div class="section__buttons mobile-show">
data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1">Смотреть бесплатно</a> <a href="#" class="btn btn_white js-video-modal"
<div>Много развивающих видео на&nbsp;нашем <a href="{{ config.SERVICE_YOUTUBE_URL|safe }}">YouTube&nbsp;канале</a></div> data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1">Смотреть бесплатный урок
<img class="emoji" src="{% static 'img/emoji-present.png' %}" /></a>
</div>
</div>
</div> </div>
</div> </div>

@ -10,12 +10,14 @@
{% endif %} {% endif %}
{% endblock ogdescription %} {% endblock ogdescription %}
{% block title %}School LIL.CITY{% endblock title %} {% block title %}Lil School{% endblock title %}
{% block body_attr %}class="main-page"{% endblock body_attr %}
{% block content %} {% block content %}
{% include "templates/blocks/messages.html" %} {% include "templates/blocks/messages.html" %}
{% include "templates/blocks/about.html" %} {% include "templates/blocks/about.html" %}
{% include "templates/blocks/video.html" %} {% include "templates/blocks/video.html" %}
{% include "templates/blocks/counters.html" %} {% include "templates/blocks/counters.html" %}
{% include "templates/blocks/students.html" %}
{% include "templates/blocks/reviews.html" %} {% include "templates/blocks/reviews.html" %}
{% include "templates/blocks/online_school.html" %} {% include "templates/blocks/online_school.html" %}
{% include "templates/blocks/teachers.html" %} {% include "templates/blocks/teachers.html" %}

@ -20,7 +20,6 @@
</div> </div>
{% include "templates/blocks/footer.html" %} {% include "templates/blocks/footer.html" %}
{% include "templates/blocks/popup_auth.html" %} {% include "templates/blocks/popup_auth.html" %}
{% include "templates/blocks/popup_school_buy.html" %}
{% if is_gift_certificate_url %} {% if is_gift_certificate_url %}
{% include "templates/blocks/popup_gift_certificate.html" %} {% include "templates/blocks/popup_gift_certificate.html" %}
{% endif %} {% endif %}

@ -51,7 +51,7 @@
{% block layer_head %}{% endblock layer_head %} {% block layer_head %}{% endblock layer_head %}
</head> </head>
<body> <body {% block body_attr %}{% endblock body_attr %}>
{% block layer_body %} {% block layer_body %}
{% endblock layer_body %} {% endblock layer_body %}
<!-- Facebook Pixel Code --> <!-- Facebook Pixel Code -->

@ -0,0 +1,144 @@
{% extends "templates/lilcity/index.html" %}
{% load static %}
{% load plural %}
{% block content %}
<div class="section">
<div class="section__center center">
<div class="packages">
{% for package in packages %}
<div class="package"
{% if forloop.counter == 4 %}style="box-shadow: 0 10px 30px 0 rgba(241, 175, 50, 0.32);"{% endif %}>
<div class="package__title subtitle">
{% if package.duration == 12 %}
<b>1</b>&nbsp;год
{% else %}
<b>{{ package.duration }}</b>&nbsp;{{ package.duration|ruplural:"месяц,месяца,месяцев" }}
{% endif %}
</div>
<div class="package__desc">{{ package.description }}</div>
<div class="package__price">
{{ package.price|floatformat }}р
{% if package.high_price %}
<div class="package__high-price">&nbsp;{{ package.high_price|floatformat }}р&nbsp;</div>
{% endif %}
</div>
<div class="package__options">
<b>Включает:</b>
<div>{{ package.options_html|safe }}</div>
</div>
<div>
<a class="package__btn btn {% if forloop.counter == 2 %}btn_light{% endif %}"
{% if forloop.counter == 1 %}
style="background-image: linear-gradient(104deg, #f8f8f8, #fff2f2)"
{% endif %}
{% if forloop.counter == 4 %}
style="background-image: linear-gradient(to bottom, #ffe790, #f9d055 45%, #f9c155); padding: 12px 9px;"
{% endif %}
{% if user.is_authenticated %}
href="{% url 'school-checkout' %}?duration={{ package.duration }}"
{% else %}
href="#" data-popup=".js-popup-auth"
{% endif %}
>{% if forloop.counter == 4 %}Вступить в Lil-Клуб{% else %}Купить{% endif %}</a>
</div>
{% if next_buy_date %}
<div style="font-size: 12px; margin-top: 10px; height: 15px;">
на {{ package.duration|rupluralize:"месяц,месяца,месяцев" }} с {{ next_buy_date|date:'j b' }}
</div>
{% endif %}
{% if forloop.counter == 4 %}
<img class="package__medal" src="{% static 'img/medal.png' %}" />
{% endif %}
</div>
{% endfor %}
<div class="mobile-show">&nbsp;</div>
</div>
</div>
</div>
<div class="section section_packages">
<div class="section__center center">
<div class="subtitle3">
Учиться вы можете и бесплатно
</div>
<div class="text2">
<p>
Приглашайте друзей и знакомых на платформу и получайте 30% от суммы их первой покупки.<br>
Просто отправьте специальную ссылку, по которой ваши друзья могут присоединиться к нам.
</p>
{% if user.is_authenticated %}
<p><a href="{% url 'user-bonuses' %}">Узнать больше о том, как зарабатывать вместе с Lil School</a></p>
{% endif %}
<p style="text-align: center; margin: 35px 0;">
<a href="#" class="package__trial-btn btn btn_white btn_shadow js-video-modal"
data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1">
Получить бесплатный урок <img src="{% static 'img/emoji_present.png' %}" /></a>
</p>
<p></p>
</div>
<div class="subtitle3">Часто задаваемые вопросы:</div>
<div class="text2">
<p>
<b>Что значит «доступ ко всем урокам школы/лагеря»?</b><br/>
Максимальный доступ включает все уроки школы:<br>
По будням с 1 сентября по 31 мая. Пять уроков в неделю.<br>
И все уроки летнего рисовального лагеря:<br>
С 1 июня по 31 августа. Три урока в неделю.
</p>
<p>
<b>Какие дисциплины входят в программу онлайн-школы и рисовального лагеря?</b><br/>
В онлайн-школе пять дисциплин:<br>
Понедельник - иллюстрация;<br>
Вторник - пластилиновая живопись;<br>
Среда - акварель;<br>
Четверг - креативное мышление;<br>
Пятница - зенарт.<br>
В рисовальном лагере облегчённая программа. Микс из трёх дисциплин ежемесячно.
</p>
<p>
<b>Сколько хранится запись урока?</b><br/>
Запись урока онлайн-школы хранится неделю. Ровно до следующего урока. В Золотом клубе уроки хранятся месяц.
</p>
<p>
<b>Если я приобрёл доступ на месяц, а после начала занятий решил взять на год?</b><br/>
В любой момент можно стать участником клуба! Новая подписка начнется на следующий день после окончания предыдущей,
а купить ее вы можете когда захотите!
</p>
<p>
<b>Могу ли я перейти на более низкий тариф?</b><br/>
Конечно можете. Компенсацию разницы мы возместим в течение 60 банковских дней.
</p>
<p>
<b>Если я не успел использовать привилегии золотого статуса в течение года?</b><br/>
Желательно использовать все привилегии в установленный срок, т.к. доступ к ним платформа предоставляет
автоматически. В других случаях администрация школы может рассмотреть сложившуюся ситуацию в индивидуальном порядке.
</p>
<p>
<b>Что делать после оплаты? Как узнать, что меня добавили в школу?</b><br/>
Нажмите на иконку в правом верхнем углу. Перейдите в свой профиль. Все, - приобретённые вами курсы хранятся там.
</p>
<p>
<b>Если я купил доступ на месяц не первого, а восьмого сентября, какая будет цена?</b><br/>
Цена будет такая же - 1990₽. Система автоматически откроет вам доступ с восьмого сентября по восьмое октября.
</p>
<p>
<b>Если я купил доступ восьмого сентября, будет ли у меня доступ к урокам, которые вышли до этой даты?</b><br/>
Система автоматически откроет вам доступ на месяц вперёд. Прошедших уроков в нём не будет.
</p>
<p>
<b>Как получить грамоту?</b><br/>
По окончании месяца занятий именная грамота автоматически придёт вам на e-mail, который вы указывали при регистрации на платформе.
</p>
<p>
<b>Можно ли купить не все дисциплины школы, а только некоторые?</b><br/>
Такой технической возможности нет.
</p>
<p>
<b>Можно ли купить неделю занятий?</b><br/>
Минимальный срок доступа - месяц.
</p>
</div>
</div>
</div>
{% endblock content %}

@ -37,7 +37,7 @@ from apps.payment.views import (
SchoolBuyView, GiftCertificatesView, GiftCertificateBuyView, SchoolBuyView, GiftCertificatesView, GiftCertificateBuyView,
GiftCertificateBuySuccessView, GiftCertificateGetView, DrawingCampBuyView) GiftCertificateBuySuccessView, GiftCertificateGetView, DrawingCampBuyView)
from .views import AboutView, IndexView, SchoolSchedulesView, LinksView from .views import AboutView, IndexView, SchoolSchedulesView, LinksView, PackagesView
# TODO trim slash in the end # TODO trim slash in the end
urlpatterns = [ urlpatterns = [
@ -103,6 +103,7 @@ urlpatterns = [
path('gift-certificate/<str:slug>/get', GiftCertificateGetView.as_view(), name='gift-certificate-get'), path('gift-certificate/<str:slug>/get', GiftCertificateGetView.as_view(), name='gift-certificate-get'),
path('faq', FAQView.as_view(), name='faq'), path('faq', FAQView.as_view(), name='faq'),
path('links', LinksView.as_view(), name='links'), path('links', LinksView.as_view(), name='links'),
path('prices', PackagesView.as_view(), name='packages'),
] ]

@ -15,3 +15,7 @@ def date_range(start, end):
def weekdays_in_date_range(start, end): def weekdays_in_date_range(start, end):
return Counter([d.isoweekday() for d in date_range(start, end)]) return Counter([d.isoweekday() for d in date_range(start, end)])
def dates_overlap(start, end, start2, end2):
return start <= end2 and start2 <= end

@ -1,4 +1,4 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta, date
from random import shuffle from random import shuffle
import short_url import short_url
@ -11,7 +11,7 @@ from paymentwall.pingback import Pingback
from apps.course.models import Course from apps.course.models import Course
from apps.school.models import SchoolSchedule from apps.school.models import SchoolSchedule
from apps.payment.models import SchoolPayment, UserGiftCertificate, Payment, DrawingCampPayment from apps.payment.models import SchoolPayment, UserGiftCertificate, Payment, DrawingCampPayment
from apps.content.models import Banner from apps.content.models import Banner, Package
User = get_user_model() User = get_user_model()
@ -98,6 +98,9 @@ class IndexView(TemplateView):
review_images = list(map(str, range(1, 107))) review_images = list(map(str, range(1, 107)))
shuffle(review_images) shuffle(review_images)
teachers = User.objects.filter(role=User.TEACHER_ROLE, show_in_mainpage=True)
if teachers.count() % 2 == 0:
teachers = teachers[:teachers.count() - 1]
context.update({ context.update({
'banners': Banner.get_for_page(Banner.PAGE_INDEX), 'banners': Banner.get_for_page(Banner.PAGE_INDEX),
@ -112,18 +115,15 @@ class IndexView(TemplateView):
'online_coming_soon': online_coming_soon, 'online_coming_soon': online_coming_soon,
'school_schedule': school_schedule, 'school_schedule': school_schedule,
'course_items': Course.shuffle(Course.objects.filter(status=Course.PUBLISHED)[:3]), 'course_items': Course.shuffle(Course.objects.filter(status=Course.PUBLISHED)[:3]),
'is_purchased': camp_payment_exists, # school_payment_exists, 'is_purchased': camp_payment_exists,
'camp_price': DrawingCampPayment.MONTH_PRICE, 'camp_price': DrawingCampPayment.MONTH_PRICE,
'min_school_price': SchoolSchedule.objects.aggregate(Min('month_price'))['month_price__min'], 'min_school_price': SchoolSchedule.objects.aggregate(Min('month_price'))['month_price__min'],
'school_schedules': SchoolSchedule.objects.filter(weekday__in=DrawingCampPayment.WEEKDAYS, is_camp=True), 'school_schedules': SchoolSchedule.objects.filter(weekday__in=DrawingCampPayment.WEEKDAYS, is_camp=True),
'school_schedules_purchased': DrawingCampPayment.WEEKDAYS if camp_payment_exists else [], # set(school_schedules_purchased), 'school_schedules_purchased': DrawingCampPayment.WEEKDAYS if camp_payment_exists else [],
'teachers': User.objects.filter(role=User.TEACHER_ROLE, show_in_mainpage=True), 'teachers': sorted(list(teachers), key=lambda t: 1 if t.email == 'sasha@lil.city' else 0, reverse=True),
'works_count': Payment.objects.filter(status__in=Payment.PW_PAID_STATUSES).count() * 7, 'works_count': Payment.objects.filter(status__in=Payment.PW_PAID_STATUSES).count() * 7,
# 'subscription_ends': school_payment.filter(add_days=False).first().date_end if school_payment_exists else None,
# 'subscription_ends_humanize': school_payment.filter(add_days=False).first().date_end_humanize if school_payment_exists else None,
'subscription_ends': camp_payment.latest('date_end').date_end if camp_payment_exists else None, 'subscription_ends': camp_payment.latest('date_end').date_end if camp_payment_exists else None,
'subscription_ends_humanize': camp_payment.latest('date_end').date_end_humanize if camp_payment_exists else None, 'subscription_ends_humanize': camp_payment.latest('date_end').date_end_humanize if camp_payment_exists else None,
'school_purchased_future': False, 'school_purchased_future': False,
'is_purchased_future': False, 'is_purchased_future': False,
@ -142,3 +142,33 @@ class SchoolSchedulesView(TemplateView):
class LinksView(TemplateView): class LinksView(TemplateView):
template_name = 'templates/lilcity/links.html' template_name = 'templates/lilcity/links.html'
class PackagesView(TemplateView):
template_name = 'templates/lilcity/packages.html'
def get_context_data(self):
context = super().get_context_data()
context['packages'] = Package.objects.all()[:4]
context['banners'] = Banner.get_for_page(Banner.PAGE_PACKAGES)[:1]
last_school_payment = None
school_end = date(now().year, 5, 31)
today = now().date()
if self.request.user.is_authenticated:
last_school_payment = SchoolPayment.objects.filter(
user=self.request.user,
date_end__gte=today,
status__in=Payment.PW_PAID_STATUSES,
).last()
context['last_school_payment'] = last_school_payment
if last_school_payment:
next_month = (last_school_payment.date_end + timedelta(1)).month
context['next_buy_date'] = last_school_payment.date_end + timedelta(1)
context['school_months_left'] = (school_end.month - next_month
if next_month <= school_end.month
else (school_end.month + 13) - next_month)
else:
context['school_months_left'] = (school_end.month - today.month
if today.month <= school_end.month
else (school_end.month + 13) - today.month)
return context

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="460px" height="200px" viewBox="0 0 460 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->
<title>Path 4</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="linearGradient-1">
<stop stop-color="#FFE2EB" offset="0%"></stop>
<stop stop-color="#D8F5F5" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Main" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Main-page" transform="translate(-420.000000, -1872.000000)" fill="url(#linearGradient-1)" fill-rule="nonzero">
<path d="M547.842222,2033.31441 C567.325204,2042.1871 613.935728,2050.03802 666.138581,2053.35195 C721.237058,2056.84969 772.754776,2054.78726 803.076869,2047.09397 C832.820717,2039.54739 854.56339,2019.81542 861.600443,1995.61066 C868.792378,1970.87317 859.821858,1944.76728 834.631473,1924.42417 C808.807191,1903.56913 757.114211,1890.40587 698.058741,1888.29284 C641.152923,1886.25672 587.043875,1894.9449 559.016359,1911.04033 C542.337069,1920.61878 531.361084,1930.16539 524.069314,1940.42993 C518.801278,1947.84568 516.755616,1952.52274 511.608582,1966.97173 C505.968408,1982.80509 501.407986,1990.80823 491.078309,1999.1047 C478.943057,2008.85135 466.577598,2021.24231 454,2036.27877 C491.686444,2023.12812 522.980771,2021.99232 547.842222,2033.31441 Z M480.325244,1986.8614 C487.7323,1980.90638 490.978009,1975.20479 495.688655,1961.96771 C501.336419,1946.0973 503.799979,1940.45918 510.228317,1931.4011 C518.968002,1919.08613 531.737121,1907.96887 550.381854,1897.25108 C581.579142,1879.31754 638.507393,1870.16761 698.211489,1872.30597 C760.504126,1874.53704 815.337821,1888.51394 844.533155,1912.11477 C874.737615,1936.53136 886.031254,1969.43061 876.945509,2000.71312 C868.229112,2030.72396 841.908219,2054.6345 806.703085,2063.57558 C774.365022,2071.78851 721.330659,2073.91377 664.657805,2070.31251 C610.562224,2066.87502 562.393742,2058.75362 540.57419,2048.80696 C514.812424,2037.06322 478.547899,2041.67354 431.702156,2063.49157 C424.041202,2067.05959 416.65058,2058.09752 421.609042,2051.25237 C441.450886,2023.86075 461.003045,2002.39579 480.325244,1986.8614 Z" id="Path-4"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@ -1,13 +1,10 @@
import $ from 'jquery'; import $ from 'jquery';
import {showNotification} from "./notification" import {showNotification} from "./notification"
import Inputmask from "inputmask"; import Inputmask from "inputmask";
import SmoothScroll from 'smooth-scroll/dist/js/smooth-scroll';
import baguetteBox from 'baguettebox.js' import baguetteBox from 'baguettebox.js'
import createHistory from 'history/createBrowserHistory' import createHistory from 'history/createBrowserHistory'
import Cookies from 'js-cookie'
import moment from 'moment'
window.$ = window.jQuery = jQuery = $; window.$ = window.jQuery = $;
window.Inputmask = Inputmask; window.Inputmask = Inputmask;
window.baguetteBox = baguetteBox; window.baguetteBox = baguetteBox;
@ -23,26 +20,6 @@ $(document).ready(function () {
} }
}); });
//===========BANNERS===============
const $banner = $('[data-banner]');
const bannerId = $banner.data('banner') + '';
const futureDate = $banner.data('future-date') + '';
if(Cookies.get('hide_banner') !== bannerId){
$banner.show();
}
$banner.on('click', '.banner__hide', function(e){
e.preventDefault();
$banner.slideUp();
Cookies.set('hide_banner', bannerId);
});
if(futureDate){
}
$banner.find('.banner__countdown')
//===========REVIEWS=============== //===========REVIEWS===============
if(window.LIL_STORE.isIndexPage){ if(window.LIL_STORE.isIndexPage){
const $reviews = $('.reviews'); const $reviews = $('.reviews');

@ -219,6 +219,15 @@ button
color: $cl color: $cl
&_pink-blue &_pink-blue
background-image: linear-gradient(100deg, #8febff, #ffa2cb) background-image: linear-gradient(100deg, #8febff, #ffa2cb)
&_disabled
opacity: 0.5
cursor: default
&:hover,
&:active
color: $cl
&_shadow
border-radius: 10px
box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.05), 0 9px 24px 0 rgba(33, 74, 211, 0.1)
&_md &_md
padding: 18px 24px 17px padding: 18px 24px 17px
+m +m
@ -853,6 +862,11 @@ a[name]
font-size: 18px font-size: 18px
font-weight: bold font-weight: bold
.subtitle3
margin-bottom: 8px
font-size: 20px
line-height: 25px
.text .text
position: relative position: relative
max-width: 620px max-width: 620px
@ -871,8 +885,8 @@ a[name]
p p
&:not(:last-child) &:not(:last-child)
margin-bottom: 35px margin-bottom: 35px
+t +m
margin: 5px 5px 15px 5px margin-bottom: 15px
&__curve &__curve
position: absolute position: absolute
pointer-events: none pointer-events: none
@ -955,12 +969,60 @@ a[name]
+f +f
font-size: 20px font-size: 20px
.text2
p
font-size: 14px
margin-bottom: 20px
line-height: 18px
.section .section
padding: 50px 0 padding: 50px 0
+t +t
padding: 30px 0 padding: 40px 0
&__column
flex: 50%
&_img
background-position: bottom center
background-size: contain
background-repeat: no-repeat
&_text
padding-right: 20px
& .text
font-size: 20px
&__title
font-size: 30px
margin-bottom: 40px
font-family: 'ProximaNova-Bold', sans-serif
&__buttons
margin-bottom: 45px
+m +m
padding: 20px 0 text-align: center
margin-bottom: 10px
& .btn
min-width: 200px
margin-bottom: 15px
margin-right: 10px
& .btn
border-radius: 10px
box-shadow: 0 11px 20px 0 rgba(0, 0, 0, 0.1)
&_main
padding: 80px 0
+m
padding: 50px 0
& .title
font-size: 30px
+m
font-size: 27px
&_gray &_gray
background: $bg background: $bg
&_pink-light &_pink-light
@ -979,6 +1041,7 @@ a[name]
transform: translateX(-50%) transform: translateX(-50%)
+t +t
max-width: calc(100% - 30px) max-width: calc(100% - 30px)
&_gradient &_gradient
background-image: linear-gradient(-225deg, $bg 0%, #FFF2F2 100%) background-image: linear-gradient(-225deg, $bg 0%, #FFF2F2 100%)
&_tabs &_tabs
@ -1010,50 +1073,140 @@ a[name]
background: $bg background: $bg
+t +t
padding: 80px 0 40px padding: 80px 0 40px
&_video &_video
padding: 70px 0 70px padding: 70px 0
background-image: linear-gradient(345deg, #eeeefa, #dff0ff)
+m
padding: 30px 0
& .btn.js-video-modal
padding-top: 5px
width: auto
box-shadow: 0 11px 24px 0 rgba(255, 147, 147, 0.3)
& img
margin-bottom: -11px
&_video &__column_img
text-align: center
&_video &__column_text
flex: 1 0 50%
&_video &__center
+m
flex-direction: column
&_video &__buttons
+m
padding-top: 15px;
&_about
padding-bottom: 0
&_about &__center
+m
flex-direction: column-reverse
&_about &__column_img
background-image: url(/static/img/girl-umbrela.png)
background-position: 40% bottom
+m
flex: 0 0 300px
&_flex &__center &_flex &__center
display: flex display: flex
&__column &_school .title
flex: 50% +m
text-align: left
&_img &_partners
.title
+m
text-align: left
.text
+m
text-align: left
&_counters
background: #eeeefa
&_counters .text_only_curve
margin-bottom: 0
& img
+m
left: -10px
bottom: -125px
&_packages &__center
width: 680px
+m
width: 100%
&_students
padding-bottom: 0
&_students &__column_img
background-image: url(/static/img/zlata.png)
height: 400px
background-position: bottom center background-position: bottom center
background-size: contain
&_text +m
padding-right: 20px height: auto
&__column .text &_students &__center:nth-child(1)
font-size: 20px +m
flex-direction: column
&__title &_students &__center:nth-child(2)
font-size: 30px margin-top: 40px
margin-bottom: 40px
font-family: 'ProximaNova-Bold', sans-serif
&__buttons +m
margin-bottom: 45px margin-top: 0
& .btn &_students &__center:nth-child(2) &__column_text
border-radius: 10px +m
box-shadow: 0 11px 20px 0 rgba(0, 0, 0, 0.1) padding: 0 0 0 10px
&_video &__column_img &__quote
text-align: center font-size: 18px
margin: -50px 0 -50px -100px
position: relative
padding: 50px 0 100px 100px
& img +m
height: 270px font-size: 14px
border-radius: 10px
box-shadow: 0 30px 60px 0 rgba(0, 0, 0, 0.2)
width: auto
&_video .btn &:before
box-shadow: 0 11px 24px 0 rgba(255, 147, 147, 0.3) background-image: url(/static/img/bubble-icon.svg?196dc3af196a)
background-size: contain
background-repeat: no-repeat
position: absolute
width: 100%
height: 80%
content: ' '
left: -2%
top: -3%
z-index: -1
+m
width: 90%;
left: 15%
top: 10%
&_counters .text_only_curve & &-text
margin-bottom: 0 margin-bottom: 20px
& &-name
text-decoration: underline
font-size: 15px
+m
font-size: 13px
.reviews-section .reviews-section
@ -1063,7 +1216,6 @@ a[name]
display: flex display: flex
height: 650px height: 650px
+m +m
padding-bottom: 20px
flex-direction: column flex-direction: column
&__title &__title
flex: 0 0 60%; flex: 0 0 60%;
@ -1072,11 +1224,6 @@ a[name]
+m +m
padding: 20px 0 0 padding: 20px 0 0
flex: 0 flex: 0
text-align: center
.text
text-align: left
+m
text-align: center
.ava .ava
display: block display: block
@ -1606,47 +1753,52 @@ a.grey-link
height: 100% height: 100%
.teachers .teachers
margin-bottom: 50px &__row
+t display: flex
margin-bottom: 0 +m
flex-direction: column
&__item &__item
display: flex display: flex
margin-bottom: 40px margin-bottom: 40px
&__ava margin-right: 40px
height: 140px padding: 30px 35px
margin-right: 25px border-radius: 10px
flex: 0 0 140px box-shadow: 0 10px 25px 0 rgba(33, 74, 211, 0.2)
width: calc(50% - 20px)
+m
width: 100%
margin-bottom: 25px
padding: 20px 15px
&:nth-child(2)
margin-right: 0px
&__left-column
margin-right: 40px
flex: 0 0 80px
+t +t
height: 100px
margin-right: 20px margin-right: 20px
flex: 0 0 100px &__ava
+m height: 80px
height: 95px
margin-right: 25px
flex: 0 0 95px
&__title &__title
margin-bottom: 5px margin-bottom: 5px
display: flex
+fb
font-size: 20px font-size: 20px
letter-spacing: 2px font-family: 'ProximaNova-Regular', sans-serif
+t letter-spacing: normal
font-size: 12px
letter-spacing: 2px
+m
display: block
&-name
flex: 1 flex: 1
+t
font-size: 18px
&__social &__social
margin-top: 15px
.social__item .social__item
margin-right: 3px margin-right: 5px
font-size: 25px font-size: 20px
+fb +fb
&__content &__content
font-size: 16px font-size: 14px
line-height: (22/16) line-height: (22/16)
&__wrap &__right-column
flex: 1 flex: 1
& .btn
margin-top: 10px
.toggle .toggle
font-size: 14px font-size: 14px
@ -1944,12 +2096,11 @@ a.grey-link
flex-wrap: wrap flex-wrap: wrap
&__item &__item
margin: 0 10px 20px margin: 0 10px 20px
flex: 0 0 calc(16.66% - 20px) flex: 0 0 calc(20% - 20px)
text-align: center text-align: center
height: 160px height: 170px
+m +m
margin: 0 5px 10px flex: 0 0 calc(50% - 20px)
flex: 0 0 100px
& a & a
height: 120px height: 120px
display: flex display: flex
@ -1961,6 +2112,7 @@ a.grey-link
font-weight: bold; font-weight: bold;
letter-spacing: 2px; letter-spacing: 2px;
text-transform: uppercase; text-transform: uppercase;
margin-top: 10px
&__pic &__pic
max-width: 100% max-width: 100%
object-fit: contain object-fit: contain
@ -2057,9 +2209,6 @@ a.grey-link
&_lg &__content &_lg &__content
padding: 0 0 0 30px padding: 0 0 0 30px
font-size: 16px font-size: 16px
&:before,
&:after
.footer .footer
padding: 50px 0 30px padding: 50px 0 30px
@ -2076,7 +2225,7 @@ a.grey-link
flex: 0 0 25% flex: 0 0 25%
+t +t
margin: 10px margin: 10px
&__row_second &__col:nth-child(2) &__row_subscr &__col:nth-child(2)
flex: 1 flex: 1
&__nav &__nav
+m +m
@ -2513,10 +2662,14 @@ a.grey-link
.main-video-preview .main-video-preview
z-index: 10 z-index: 10
position: relative position: relative
box-shadow: 0 10px 100px rgba(0,0,0,0.20) box-shadow: 0 30px 60px 0 rgba(0, 0, 0, 0.2)
cursor: pointer
max-height: 270px
border-radius: 10px
max-width: 100%
+m
width: 100% width: 100%
height: auto height: auto
cursor: pointer
.head .head
display: flex display: flex
@ -3982,16 +4135,6 @@ a.grey-link
&_info &_info
background: $green background: $green
.mobile-hide
+m
display: none
.mobile-show
display: none
+m
display: block
.school .school
display: flex display: flex
position: relative position: relative
@ -4002,6 +4145,11 @@ a.grey-link
margin-bottom: -40px margin-bottom: -40px
+m +m
margin: 0 -10px -30px margin: 0 -10px -30px
&_three-col
margin-top: 50px
+m
flex-direction: column
margin-top: 40px
&__col &__col
padding: 0 15px padding: 0 15px
text-align: center text-align: center
@ -4012,6 +4160,10 @@ a.grey-link
+m +m
margin-bottom: 30px margin-bottom: 30px
padding: 0 10px padding: 0 10px
&_three-col &__col
flex: 0 0 33%
+t
flex: 0 0 33%
&__preview &__preview
margin-bottom: 25px margin-bottom: 25px
font-size: 0 font-size: 0
@ -4033,11 +4185,6 @@ a.grey-link
text-transform: uppercase text-transform: uppercase
+t +t
font-size: 10px font-size: 10px
&_main &__col
+t
flex: 0 0 25%
+m
flex: 0 0 50%
&_main &__preview &_main &__preview
margin-bottom: 10px margin-bottom: 10px
font-size: 32px font-size: 32px
@ -4488,7 +4635,8 @@ a
padding-top: 0 padding-top: 0
+m +m
padding-left: 0 padding-left: 0
height: 220px height: 260px
flex-direction: column
&__text &__text
font-size: 30px font-size: 30px
text-shadow: none text-shadow: none
@ -4498,7 +4646,6 @@ a
+m +m
font-size: 16px font-size: 16px
width: auto width: auto
font-weight: bold
&__link &__link
font-size: 15px font-size: 15px
color: black color: black
@ -4513,10 +4660,16 @@ a
text-transform: uppercase text-transform: uppercase
font-family: 'ProximaNova-Bold' font-family: 'ProximaNova-Bold'
box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.05), 0 9px 24px 0 rgba(33, 74, 211, 0.1) box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.05), 0 9px 24px 0 rgba(33, 74, 211, 0.1)
z-index: 1
+m +m
margin-top: 20px margin-top: 20px
font-size: 10px font-size: 10px
padding: 10px 14px padding: 10px 14px
left: 50%
position: absolute
margin-left: -114px
width: 200px
bottom: 35px
&__link:hover &__link:hover
background: #ddd background: #ddd
&__image-column &__image-column
@ -4524,6 +4677,8 @@ a
text-align: center text-align: center
position: relative position: relative
padding-right: 20px padding-right: 20px
+m
flex: 1
& img & img
position: absolute position: absolute
bottom: 0 bottom: 0
@ -4539,6 +4694,7 @@ a
padding-top: 40px padding-top: 40px
+m +m
padding-top: 20px padding-top: 20px
flex: 0
&__countdown-title &__countdown-title
color: black color: black
font-size: 15px font-size: 15px
@ -4549,6 +4705,11 @@ a
position: absolute position: absolute
transform: translateX(-50%) transform: translateX(-50%)
left: 50% left: 50%
padding: 5px
background: rgba(255, 255, 255, 0.5)
border-radius: 5px
+m
padding: 5px 20px
&__countdown &__countdown
display: flex display: flex
color: black color: black
@ -4699,6 +4860,9 @@ a
height: 200px height: 200px
+t +t
margin-bottom: 10px margin-bottom: 10px
+m
margin-left: auto
margin-right: auto
&__cover &__cover
object-fit: cover; object-fit: cover;
width: 100%; width: 100%;
@ -4977,3 +5141,95 @@ a
height: auto height: auto
max-height: 70px max-height: 70px
z-index: 1 z-index: 1
.emoji
height: 32px
margin-bottom: -7px
.packages
display: flex
overflow-x: auto
background: white
padding: 30px
margin: -50px
+m
margin: 0
.package
position: relative
border-radius: 10px
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.1)
margin-right: 20px
padding: 20px
width: calc(25% - 20px)
display: flex
flex-direction: column
text-align: center
+m
min-width: 190px
padding: 20px 28px
&__btn
width: 100%
&__title
font-size: 14px
text-align: center
margin-top: 20px
font-family: 'ProximaNova-Regular', sans-serif
+m
margin-top: 0
&__desc
font-size: 13px
height: 35px
&__price
font-size: 40px
margin: 20px 0 40px
+m
margin: 17px 0 13px
&__high-price
text-decoration: line-through
font-size: 15px
color: #9b9b9b
height: 15px
margin-bottom: -15px
+m
margin-top: -15px
margin-bottom: 0
&__options
padding: 30px 0
border-image-source: linear-gradient(to right, #ffe2eb, #d8f5f5)
border-image-slice: 1
border-top: 1px solid
text-align: left
font-size: 12px
line-height: 18px
flex: 1
+m
padding: 19px 0 30px
& p
margin-top: 6px
&__medal
position: absolute
height: 53px
right: 18px
top: -17px
&__trial-btn img
width: 24px
margin-bottom: -6px
.mobile-hide
+m
display: none
.mobile-show
display: none
+m
display: block

Loading…
Cancel
Save