LIL-684 Просмотр пробного урока - Добавить форму захвата почты

remotes/origin/feature/LIL-711
gzbender 7 years ago
parent 0c073e9661
commit a1c391271e
  1. 3
      api/v1/urls.py
  2. 43
      api/v1/views.py
  3. 4
      apps/school/templates/blocks/schedule_item.html
  4. 28
      project/templates/blocks/popup_capture_email.html
  5. 2
      project/templates/blocks/popup_school_buy.html
  6. 2
      project/templates/blocks/teachers.html
  7. 1
      project/templates/lilcity/index.html
  8. 2
      web/package.json
  9. 2
      web/src/js/app.js
  10. 7
      web/src/js/modules/api.js
  11. 132
      web/src/js/modules/popup.js
  12. 6
      web/src/js/utils.js
  13. 7
      web/src/sass/_common.sass

@ -19,7 +19,7 @@ from .views import (
SchoolScheduleViewSet, LiveLessonViewSet,
PaymentViewSet, ObjectCommentsViewSet,
ContestViewSet, ContestWorkViewSet,
AuthorBalanceUsersViewSet)
AuthorBalanceUsersViewSet, CaptureEmail)
router = DefaultRouter()
router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
@ -64,6 +64,7 @@ schema_view = get_schema_view(
)
urlpatterns = [
path('capture-email/', CaptureEmail.as_view(), name='capture-email'),
path('author-balance-users/', AuthorBalanceUsersViewSet.as_view(), name='author-balance-users'),
path('api-token-auth/', ObtainToken.as_view(), name='api-token-auth'),
path('temp-auth-token/', ObtainTempToken.as_view(), name='temp-auth-token'),

@ -1,3 +1,4 @@
import json
from datetime import datetime
from decimal import Decimal
@ -71,6 +72,7 @@ from apps.payment.models import (
from apps.school.models import SchoolSchedule, LiveLesson
from apps.user.models import AuthorRequest
from project.pusher import pusher
from project.sengrid import get_sendgrid_client
User = get_user_model()
@ -656,3 +658,44 @@ class ContestWorkViewSet(ExtendedModelViewSet):
if ContestWork.objects.filter(user=user).exists():
return Response(status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
class CaptureEmail(views.APIView):
authentication_classes = ()
def post(self, request):
list_id = None
list_name = 'captured-emails'
recipient_id = None
email = request.data.get('email')
sg = get_sendgrid_client()
# берем все списки
response = sg.client.contactdb.lists.get()
if response.status_code != 200:
return Response({'error': 'Cannot get list of lists'}, status=status.HTTP_400_BAD_REQUEST)
# ищем нужный список
for sg_list in response.to_dict.get('lists'):
if sg_list.get('name') == list_name:
list_id = sg_list.get('id')
break
# не нашли - создаем
if not list_id:
response = sg.client.contactdb.lists.post(request_body={'name': list_name})
if response.status_code != 201:
return Response({'error': 'List was not created'}, status=status.HTTP_400_BAD_REQUEST)
list_id = response.to_dict.get('id')
# добавляем получателя
response = sg.client.contactdb.recipients.patch(request_body=[{
'email': email,
}])
if response.status_code != 201:
return Response({'error': 'Cannot update recipients'}, status=status.HTTP_400_BAD_REQUEST)
recipient_id = response.to_dict.get('persisted_recipients')[0]
# добавляем получателя в отдельный список
response = sg.client.contactdb.lists._(list_id).recipients._(recipient_id).post()
if response.status_code != 201:
return Response({'error': 'Cannot add recipient to list'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'status': 'ok'})

@ -5,7 +5,7 @@
<div class="timing__day{% if school_schedule.is_online %} active{% endif %}">
{{ school_schedule }}
{% if not is_purchased and request.user_agent.is_mobile and school_schedule.trial_lesson %}
<a class="timing__trial-lesson js-video-modal" href="#" data-video-url="{{ school_schedule.trial_lesson }}">Пробный урок</a>
<a class="timing__trial-lesson js-video-modal" href="#" data-trial-lesson="1" data-video-url="{{ school_schedule.trial_lesson }}">Пробный урок</a>
{% endif %}
</div>
{% if is_purchased and live_lesson %}
@ -21,7 +21,7 @@
{% include './day_pay_btn.html' %}
{% endif %}
{% if not is_purchased and not request.user_agent.is_mobile and school_schedule.trial_lesson %}
<a class="timing__trial-lesson js-video-modal" href="#" data-video-url="{{ school_schedule.trial_lesson }}">Пробный урок</a>
<a class="timing__trial-lesson js-video-modal" href="#" data-trial-lesson="1" data-video-url="{{ school_schedule.trial_lesson }}">Пробный урок</a>
{% endif %}
</div>
</div>

@ -0,0 +1,28 @@
{% load static %}
<div class="popup js-popup-capture-email" data-manual-close="1">
<div class="popup__wrap popup__wrap_sm js-popup-wrap">
<button class="popup__close js-popup-close">
<svg class="icon icon-close">
<use xlink:href={% static "img/sprite.svg" %}#icon-close></use>
</svg>
</button>
<div class="popup__body">
<div class="capture-email" style="padding:20px 20px 25px;">
<div class="subtitle2">Чтобы посмотреть продолжение пробного урока, необходимо указать почту</div>
<form>
{% csrf_token %}
<div class="field">
<div class="field__label">ПОЧТА</div>
<div class="field__wrap"><input class="field__input capture-email__email" type="email"
name="email"
placeholder="name@website.com" tabindex="1"></div>
<div class="capture-email__error field__error"></div>
</div>
<div style="text-align: center;">
<button type="submit" class="capture-email__btn btn btn_light" tabindex="3">Подтвердить</button>
</div>
</form>
</div>
</div>
</div>
</div>

@ -45,7 +45,7 @@
Куплено
{% else %}
{% if school_schedule.trial_lesson %}
<a class="js-video-modal" data-video-url="{{ school_schedule.trial_lesson }}" href="">Пробный урок</a>
<a class="js-video-modal" data-video-url="{{ school_schedule.trial_lesson }}" data-trial-lesson="1" href="">Пробный урок</a>
{% endif %}
{% endif %}
</span>

@ -25,7 +25,7 @@
{% endif %}
</div>
{% if teacher.trial_lesson %}
<a data-video-url="{{ teacher.trial_lesson }}" href="#" class="btn btn_light js-video-modal">ПРОБНЫЙ УРОК</a>
<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">

@ -147,6 +147,7 @@
{% endif %}
{% include "templates/blocks/popup_course_lock.html" %}
{% include "templates/blocks/popup_subscribe.html" %}
{% include "templates/blocks/popup_capture_email.html" %}
</div>
{% include 'templates/blocks/lil_store_js.html' %}

@ -48,7 +48,7 @@
"jquery": "^3.3.1",
"js-cookie": "^2.2.0",
"lodash.debounce": "^4.0.8",
"modal-video": "^2.4.2",
"modal-video": "git+https://github.com/gzbender/modal-video.git",
"moment": "^2.20.1",
"owl.carousel": "^2.2.0",
"slugify": "^1.2.9",

@ -3,8 +3,6 @@
*/
import 'ilyabirman-likely/release/likely.js';
import 'ilyabirman-likely/release/likely.css';
import "modal-video/js/jquery-modal-video.min.js";
import "modal-video/css/modal-video.min.css";
import "./modules/common";
import "./modules/header";
import "./modules/search";

@ -479,5 +479,12 @@ export const api = {
'Authorization': `Token ${window.LIL_STORE.accessToken}`,
}
});
},
captureEmail: (email) => {
return api.post('/api/v1/capture-email/', {email}, {
headers: {
'Authorization': `Token ${window.LIL_STORE.accessToken}`,
}
});
}
};

@ -1,11 +1,66 @@
import $ from 'jquery';
import moment from 'moment';
import {api} from './api';
import "modal-video/js/jquery-modal-video.js";
import "modal-video/css/modal-video.min.css";
import {email as emailValid} from 'vuelidate/lib/validators';
import Cookies from 'js-cookie'
moment.locale('ru');
var selectedWeekdays = {};
$(document).ready(function () {
let body = $('body'),
popup = $('.popup.visible.open'),
prevPopup = null;
// CAPTURE EMAIL
const EMAIL_CAPTURED_COOKIE = 'email-captured';
if(window.LIL_STORE.user.id){
Cookies.remove(EMAIL_CAPTURED_COOKIE);
}
$('.js-popup-capture-email .js-popup-close').on('click', function(e){
e.preventDefault();
hidePopup().then(() => {
popup = prevPopup;
});
$('.modal-video').remove();
});
const captureEmail = (callback) => {
prevPopup = popup;
popup = $('.js-popup-capture-email');
const $modalVideo = $('.modal-video');
const $email = popup.find('.capture-email__email');
const $error = popup.find('.capture-email__error');
$modalVideo.css('opacity', 0);
$email.val('');
$error.text('');
popup.css('z-index', 1000001);
showPopup();
popup.find('.capture-email__btn').unbind('click').click(e => {
e.preventDefault();
const email = $email.val();
if(! email){
$error.text('Пожалуйста, укажите почту');
return;
}
if(! emailValid(email)){
$error.text('Пожалуйста, укажите коректную почту');
return;
}
api.captureEmail(email);
hidePopup().then(() => {
popup = prevPopup;
});
$modalVideo.css('opacity', 1);
Cookies.set(EMAIL_CAPTURED_COOKIE, 1);
callback();
});
};
$(".js-video-modal").each(function(){
const $this = $(this);
const url = $this.data('videoUrl');
@ -31,11 +86,65 @@ $(document).ready(function () {
}
$this.attr('data-video-id', videoId);
$this.attr('data-video-url', '');
$this.modalVideo({ channel });
$this.attr('data-channel', channel);
$this.modalVideo({ channel, jsapi: true });
});
let body = $('body'),
popup = $('.popup.visible.open');
$(".js-video-modal").on('player-created', e => {
if(window.LIL_STORE.user.id || ! $(e.target).data('trialLesson') || Cookies.get(EMAIL_CAPTURED_COOKIE)){
return;
}
let stopVideo = () => {};
let playVideo = () => {};
const channel = $(e.target).data('channel');
const $iframe = $('.modal-video-movie-wrap iframe');
const player = e.detail.player;
let timeout = null;
const interval = 1000 * 10;// 60 * 2; // 2 min
if(channel == 'youtube'){
const pauseVideo = () => {
clearTimeout(timeout);
if(! $('.modal-video').length){
return;
}
player.pauseVideo();
captureEmail(() => {
player.playVideo();
});
}
window.onYTPlayerStateChange = (event) => {
if(event.data == YT.PlayerState.PLAYING && ! timeout){
timeout = setTimeout(pauseVideo, interval);
}
if(event.data == YT.PlayerState.ENDED && timeout){
clearTimeout(timeout);
}
}
player.addEventListener('onStateChange', 'onYTPlayerStateChange');
}
else if (channel == 'vimeo'){
const pauseVideo = () => {
clearTimeout(timeout);
if(! $('.modal-video').length){
return;
}
player.pause();
captureEmail(() => {
player.play();
});
}
player.on('play', () => {
if(! timeout){
timeout = setTimeout(pauseVideo, interval);
}
})
player.on('ended', () => {
if(timeout){
clearTimeout(timeout);
}
});
}
});
body.on('click', '[data-popup]', function(e){
const $this = $(this);
@ -50,7 +159,6 @@ $(document).ready(function () {
showPopup();
if(data === '.js-popup-buy') {
console.log('reset selected');
popup.data('date-start', $this.data('date-start') || '');
popup.data('day', $this.data('day') || '');
$('[data-day]').prop('checked', false);
@ -140,12 +248,15 @@ $(document).ready(function () {
});
$('.js-popup-close').on('click', function(e){
if(popup.data('manual-close')){
return;
}
e.preventDefault();
hidePopup();
});
body.on('click', '.js-outer', function(){
if (popup !== undefined) {
if (popup !== undefined && ! popup.data('manual-close')) {
hidePopup();
}
});
@ -155,16 +266,22 @@ $(document).ready(function () {
});
$(document).keyup(function(e){
if (e.keyCode === 27) hidePopup();
if (e.keyCode === 27 && ! popup.data('manual-close')) {
hidePopup();
}
});
function showPopup(){
function showPopup(popupName){
if(! popup && popupName){
popup = $(popupName);
}
body.addClass('no-scroll');
popup.addClass('open');
return new Promise((resolve) => {
setTimeout(function(){
popup.addClass('visible');
resolve();
$(document).trigger('popup-opened', popup);
}, 100);
});
}
@ -181,6 +298,7 @@ $(document).ready(function () {
setTimeout(function(){
popup.removeClass('open');
resolve();
$(document).trigger('popup-closed', popup);
}, 300);
});
}

@ -3,3 +3,9 @@ export const rupluralize = (value, args) => {
digit = digit[digit.length - 1];
return value + ' ' + args[digit == '1' ? 0 : ('234'.search(digit) > -1 ? 1 : 2)];
}
export const loadScript = (url, onload) => {
const tag = document.createElement('script');
tag.url = url;
document.getElementsByTagName('body');
}

@ -827,6 +827,11 @@ a[name]
+t
text-align: center
.subtitle2
margin-bottom: 20px
font-size: 18px
font-weight: bold
.text
position: relative
max-width: 620px
@ -2383,6 +2388,8 @@ a.grey-link
border-radius: 3px
transform: scale(.9)
transition: transform .2s
&_sm
max-width: 500px
&_md
max-width: 620px
&_lg

Loading…
Cancel
Save