remotes/origin/feature/drawing-camp
commit
d770acb648
47 changed files with 715 additions and 258 deletions
@ -0,0 +1,28 @@ |
|||||||
|
# Generated by Django 2.0.7 on 2019-06-05 13:38 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('config', '0013_config_main_page_video_preview_img'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='config', |
||||||
|
name='NUMBER_OF_CITIES', |
||||||
|
field=models.IntegerField(default=107), |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='config', |
||||||
|
name='NUMBER_OF_COUNTRIES', |
||||||
|
field=models.IntegerField(default=81), |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='config', |
||||||
|
name='NUMBER_OF_STUDENTS', |
||||||
|
field=models.IntegerField(default=17000), |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
{% extends "notification/email/_base.html" %} |
||||||
|
{% load settings %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
{% if product_type == 'course' %} |
||||||
|
<p>Курс ждет вас по ссылке <a href="https://{% setting 'MAIN_HOST' %}{{ url }}"> |
||||||
|
https://{% setting 'MAIN_HOST' %}{{ url }}</a></p> |
||||||
|
{% endif %} |
||||||
|
{% if product_type == 'school' %} |
||||||
|
<p>Школа ждет вас по ссылке <a href="https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}"> |
||||||
|
https://{% setting 'MAIN_HOST' %}{% url 'school:school' %}</a></p> |
||||||
|
{% endif %} |
||||||
|
{% if product_type == 'drawing_camp' %} |
||||||
|
<p>Рисовальный лагерь ждет вас по ссылке <a href="https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}"> |
||||||
|
https://{% setting 'MAIN_HOST' %}{% url 'school:drawing-camp' %}</a></p> |
||||||
|
{% endif %} |
||||||
|
<p>Так же вы можете найти ссылку в личном кабинете в разделе «Мои покупки».</p> |
||||||
|
|
||||||
|
<p>Занимайтесь с удовольствием!</p> |
||||||
|
|
||||||
|
<p>Команда «Lil School».</p> |
||||||
|
{% endblock content %} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
# Generated by Django 2.0.7 on 2019-06-06 21:05 |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('user', '0031_user_review_url'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='Child', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('first_name', models.CharField(max_length=30, verbose_name='Имя ребенка')), |
||||||
|
('last_name', models.CharField(blank=True, default='', max_length=150, verbose_name='Фамилия ребенка')), |
||||||
|
('gender', models.CharField(choices=[('n', 'не указан'), ('m', 'Мужчина'), ('f', 'Женщина')], default='n', max_length=1, verbose_name='Пол ребенка')), |
||||||
|
('birthday', models.DateField(blank=True, null=True, verbose_name='День рождения ребенка')), |
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='childs', to=settings.AUTH_USER_MODEL)), |
||||||
|
], |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
# Generated by Django 2.0.7 on 2019-06-07 20:48 |
||||||
|
|
||||||
|
from django.db import migrations |
||||||
|
|
||||||
|
|
||||||
|
def add_childs(apps, schema_editor): |
||||||
|
User = apps.get_model('user', 'User') |
||||||
|
Child = apps.get_model('user', 'Child') |
||||||
|
for user in User.objects.exclude(child_first_name=''): |
||||||
|
Child.objects.get_or_create(user=user, first_name=user.child_first_name, last_name=user.child_last_name, |
||||||
|
gender=user.child_gender, birthday=user.child_birthday) |
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('user', '0032_child'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.RunPython(add_childs), |
||||||
|
] |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
# Generated by Django 2.0.7 on 2019-06-12 18:52 |
||||||
|
|
||||||
|
from django.db import migrations |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('user', '0033_add_childs'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.RemoveField( |
||||||
|
model_name='user', |
||||||
|
name='child_birthday', |
||||||
|
), |
||||||
|
migrations.RemoveField( |
||||||
|
model_name='user', |
||||||
|
name='child_first_name', |
||||||
|
), |
||||||
|
migrations.RemoveField( |
||||||
|
model_name='user', |
||||||
|
name='child_gender', |
||||||
|
), |
||||||
|
migrations.RemoveField( |
||||||
|
model_name='user', |
||||||
|
name='child_last_name', |
||||||
|
), |
||||||
|
] |
||||||
@ -1,10 +1,10 @@ |
|||||||
<div class="section section_video"> |
<div class="section section_video"> |
||||||
<div class="section__center center center_sm" style="text-align: center;"> |
<div class="section__center center center_sm" style="text-align: center;"> |
||||||
<div class="title">Пробный урок</div> |
<div class="title">Пробный урок</div> |
||||||
<img class="main-video-preview js-video-modal" data-video-url="{{ config.MAIN_PAGE_VIDEO_URL }}" 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;" |
<a href="#" class="btn js-video-modal btn_stroke-black" style="margin: 20px;" |
||||||
data-video-url="{{ config.MAIN_PAGE_VIDEO_URL }}" data-trial-lesson="1">Смотреть бесплатно</a> |
data-video-url="{{ config.MAIN_PAGE_VIDEO_URL|safe }}" data-trial-lesson="1">Смотреть бесплатно</a> |
||||||
<div>Много развивающих видео на нашем <a href="{{ config.SERVICE_YOUTUBE_URL }}">YouTube канале</a></div> |
<div>Много развивающих видео на нашем <a href="{{ config.SERVICE_YOUTUBE_URL|safe }}">YouTube канале</a></div> |
||||||
</div> |
</div> |
||||||
</div> |
</div> |
||||||
|
|||||||
@ -0,0 +1,120 @@ |
|||||||
|
<template> |
||||||
|
<div class="user-child-form form__group"> |
||||||
|
<div class="form__title">Карточка ребёнка</div> |
||||||
|
<div class="user-child-form__description"> |
||||||
|
Вся информация конфиденциальна и не передается третьим лицам. Необходима только для персонализации наград, |
||||||
|
поздравлений с Днем Рождения и других персонализированных акций. |
||||||
|
</div> |
||||||
|
<div class="tabs"> |
||||||
|
<div class="user-child-form__tabs tabs__nav"> |
||||||
|
<a class="user-child-form__tab tabs__btn" v-for="(child, index) in childs" :key="index" href="#" |
||||||
|
v-bind:class="{active: selectedIndex == index}" @click.prevent="select(index)"> |
||||||
|
{{ child.first_name ? (child.first_name + ' ' + child.last_name) : ('Ребенок ' + (index || '')) }}</a> |
||||||
|
<a href="#" class="tabs__btn" @click.prevent="add()">Добавить ребенка</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="tabs__container"> |
||||||
|
<div v-for="(child, index) in childs" :key="index" class="tabs__item js-tabs-item" |
||||||
|
v-bind:style="{display: selectedIndex == index ? 'block' : ''}"> |
||||||
|
<div class="form__fieldset"> |
||||||
|
<input type="hidden" name="child_id" :value="child.id" /> |
||||||
|
<div class="form__field field" v-bind:class="{error: child.errors && child.errors.gender}"> |
||||||
|
<div class="field__label">ИМЯ РЕБЕНКА</div> |
||||||
|
<div class="field__wrap"> |
||||||
|
<input name='child_first_name' class="field__input" type="text" placeholder="Имя" |
||||||
|
v-model="child.first_name"> |
||||||
|
</div> |
||||||
|
<div v-if="child.errors && child.errors.first_name" class="field__error">{{ child.errors.first_name }}</div> |
||||||
|
</div> |
||||||
|
<div class="form__field field" v-bind:class="{error: child.errors && child.errors.last_name}"> |
||||||
|
<div class="field__label">ФАМИЛИЯ РЕБЕНКА</div> |
||||||
|
<div class="field__wrap"> |
||||||
|
<input name='child_last_name' id="child-last-name" class="field__input" type="text" placeholder="Фамилия" |
||||||
|
v-model="child.last_name"> |
||||||
|
</div> |
||||||
|
<div v-if="child.errors && child.errors.last_name" class="field__error">{{ child.errors.last_name }}</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form__fieldset"> |
||||||
|
<div class="form__field field" v-bind:class="{error: child.errors && child.errors.birthday}"> |
||||||
|
<div class="field__label">ДАТА РОЖДЕНИЯ</div> |
||||||
|
<div class="field__wrap"> |
||||||
|
<vue-datepicker input-class="field__input" name="child_birthday" language="ru" format="dd/MM/yyyy" |
||||||
|
v-model="child.birthday" placeholder="dd/mm/yyyy"/> |
||||||
|
</div> |
||||||
|
<div v-if="child.errors && child.errors.birthday" class="field__error">{{ child.errors.birthday }}</div> |
||||||
|
</div> |
||||||
|
<div class="form__field field" v-bind:class="{error: child.errors && child.errors.gender}"> |
||||||
|
<div class="field__label">ПОЛ</div> |
||||||
|
<div class="field__wrap"> |
||||||
|
<lil-select :value.sync="child.gender" :options="genders" value-key="0" title-key="1"/> |
||||||
|
<input name='child_gender' type="hidden" v-model="child.gender"> |
||||||
|
</div> |
||||||
|
<div v-if="child.errors && child.errors.gender" class="field__error">{{ child.errors.gender }}</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<a href="#" @click.prevent="remove(index)">Удалить</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import DatePicker from 'vuejs-datepicker'; |
||||||
|
import LilSelect from './inputs/LilSelect'; |
||||||
|
|
||||||
|
export default { |
||||||
|
name: "childs", |
||||||
|
props: ['childs'], |
||||||
|
data() { |
||||||
|
return { |
||||||
|
selectedIndex: 0, |
||||||
|
selectedChild: null, |
||||||
|
genders: [ |
||||||
|
['n', 'М / Ж'], |
||||||
|
['f', 'Ж'], |
||||||
|
['m', 'М'], |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
add(){ |
||||||
|
this.childs.push({ |
||||||
|
first_name: '', |
||||||
|
last_name: '', |
||||||
|
birthday: '', |
||||||
|
gender: 'n', |
||||||
|
errors: {}, |
||||||
|
}); |
||||||
|
this.select(this.childs.length - 1); |
||||||
|
}, |
||||||
|
remove(index){ |
||||||
|
if(! confirm('Вы действительно хотите удалить данные о ребенке?')){ |
||||||
|
return; |
||||||
|
} |
||||||
|
this.childs.splice(index, 1); |
||||||
|
if(! this.childs.length){ |
||||||
|
this.add(); |
||||||
|
} |
||||||
|
else if(this.selectedIndex == index){ |
||||||
|
this.select(0); |
||||||
|
} |
||||||
|
}, |
||||||
|
select(index){ |
||||||
|
this.selectedIndex = index; |
||||||
|
this.selectedChild = this.childs[index]; |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted(){ |
||||||
|
for(let i in this.childs){ |
||||||
|
if(this.childs[i].errors){ |
||||||
|
this.select(i); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { |
||||||
|
'vue-datepicker': DatePicker, |
||||||
|
LilSelect, |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 93 KiB |
@ -0,0 +1,62 @@ |
|||||||
|
import $ from 'jquery'; |
||||||
|
import {loadScript} from '../utils'; |
||||||
|
|
||||||
|
function getVideoPopup($videoEl){ |
||||||
|
const $container = $videoEl.parent(); |
||||||
|
let $popup = $container.children('.video-ended-popup'); |
||||||
|
if(! $popup[0]){ |
||||||
|
$popup = $('<div class="video-ended-popup">' + |
||||||
|
'<div class="loading-loader"></div>' + |
||||||
|
'<div class="video-ended-popup__like-btn"></div></div>'); |
||||||
|
$container.append($popup); |
||||||
|
} |
||||||
|
return $popup; |
||||||
|
} |
||||||
|
|
||||||
|
$(document).ready(function () { |
||||||
|
$('.js-video').each(function (){ |
||||||
|
const $iframe = $(this); |
||||||
|
if($iframe.data('isYoutube')){ |
||||||
|
|
||||||
|
} |
||||||
|
if($iframe.data('isVimeo')){ |
||||||
|
loadScript('https://player.vimeo.com/api/player.js').then(() => { |
||||||
|
const player = new Vimeo.Player(this); |
||||||
|
player.on('pause', function(data) { |
||||||
|
if(data.percent == 1){ |
||||||
|
const $popup = getVideoPopup($iframe); |
||||||
|
$popup.show().animate({opacity: 1}, 200); |
||||||
|
if (document.fullscreenElement){ |
||||||
|
document.exitFullscreen(); |
||||||
|
} |
||||||
|
const courseId = $iframe.data('courseId'); |
||||||
|
if(courseId && window.LIL_STORE.user.id && !window.LIL_STORE.data.courseLiked){ |
||||||
|
$popup.addClass('video-ended-popup_loading'); |
||||||
|
$.get('/api/v1/likes/course-liked/', { |
||||||
|
course_id: courseId, |
||||||
|
user_id: window.LIL_STORE.user.id |
||||||
|
}).then(response => { |
||||||
|
if(! response.is_liked){ |
||||||
|
$popup.addClass('video-ended-popup_like'); |
||||||
|
$popup.find('.video-ended-popup__like-btn').click(() => { |
||||||
|
$.post(`/course/${courseId}/like`).then(response => { |
||||||
|
$popup.removeClass('video-ended-popup_like'); |
||||||
|
window.LIL_STORE.data.courseLiked = response.success; |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
$popup.removeClass('video-ended-popup_loading'); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
player.on('play', function() { |
||||||
|
const $p = getVideoPopup($iframe); |
||||||
|
if($p.is(':visible')){ |
||||||
|
$p.animate({opacity: 0}, 800).then(() => {$p.hide().attr('class', 'video-ended-popup');}); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
@ -0,0 +1 @@ |
|||||||
|
import "../modules/content"; |
||||||
@ -0,0 +1 @@ |
|||||||
|
import "../modules/content"; |
||||||
@ -1,14 +1,21 @@ |
|||||||
export const rupluralize = (value, args, addValue=true) => { |
export const rupluralize = (value, args, addValue = true) => { |
||||||
let digit = Math.trunc(value) + ''; |
let digit = Math.trunc(value) + ''; |
||||||
digit = digit[digit.length - 1]; |
digit = digit[digit.length - 1]; |
||||||
return (addValue ? value + ' ' : '') + |
return (addValue ? value + ' ' : '') + |
||||||
args[(+value > 10 && +value < 20) |
args[(+value > 10 && +value < 20) |
||||||
? 2 |
? 2 |
||||||
: (digit == '1' ? 0 : ('234'.search(digit) > -1 ? 1 : 2))]; |
: (digit == '1' ? 0 : ('234'.search(digit) > -1 ? 1 : 2))]; |
||||||
} |
}; |
||||||
|
|
||||||
export const loadScript = (url, onload) => { |
export const loadScript = (url, onload) => { |
||||||
const tag = document.createElement('script'); |
return new Promise(resolve => { |
||||||
tag.url = url; |
const script = document.createElement('script'); |
||||||
document.getElementsByTagName('body'); |
script.async = true; |
||||||
} |
document.body.appendChild(script); |
||||||
|
script.onload = function () { |
||||||
|
onload && onload.apply(this, arguments); |
||||||
|
resolve.apply(this, arguments); |
||||||
|
}; |
||||||
|
script.src = url; |
||||||
|
}); |
||||||
|
}; |
||||||
|
|||||||
Loading…
Reference in new issue