Merge branch 'master' of https://gitlab.com/lilcity/backend into feature/LIL-670

remotes/origin/hotfix/LIL-691
gzbender 7 years ago
commit 98c3462179
  1. 98
      api/v1/serializers/mixins.py
  2. 6
      api/v1/views.py
  3. 23
      apps/payment/models.py
  4. 46
      apps/payment/views.py
  5. 6
      apps/school/templates/summer/prolong_btn.html
  6. 6
      apps/school/templates/summer/schedule_purchased.html
  7. 5
      apps/school/views.py
  8. 16
      project/context_processors.py
  9. 2
      project/settings.py
  10. 3
      project/templates/blocks/lil_store_js.html
  11. 37
      project/templates/blocks/popup_buy.html
  12. 2
      project/templates/lilcity/edit_index.html
  13. 6
      project/urls.py
  14. 136
      web/src/components/ContestRedactor.vue
  15. 94
      web/src/components/CourseRedactor.vue
  16. 68
      web/src/components/LessonRedactor.vue
  17. 87
      web/src/components/blocks/BlockContent.vue
  18. 20
      web/src/components/blocks/BlockImages.vue
  19. 3
      web/src/components/blocks/Image.vue
  20. 18
      web/src/js/app.js
  21. 17
      web/src/js/contest-redactor.js
  22. 20
      web/src/js/course-redactor.js
  23. 195
      web/src/js/modules/api.js
  24. 59
      web/src/js/modules/comments_vue.js
  25. 68
      web/src/js/modules/popup.js

@ -32,35 +32,23 @@ class DispatchContentMixin(object):
if 'id' in cdata and cdata['id']:
t = Text.objects.get(id=cdata.pop('id'))
serializer = TextCreateSerializer(t, data=cdata)
if serializer.is_valid():
serializer.save()
else:
serializer = TextCreateSerializer(data=cdata)
if serializer.is_valid():
serializer.save()
if serializer.is_valid():
serializer.save()
elif ctype == 'image':
if 'id' in cdata and cdata['id']:
image = Image.objects.get(id=cdata.pop('id'))
serializer = ImageCreateSerializer(image, data=cdata)
if serializer.is_valid():
image = serializer.save()
else:
continue
try:
image_object = ImageObject.objects.get(id=cdata['img'])
except ImageObject.DoesNotExist:
pass
else:
image.img = image_object
image.save()
else:
serializer = ImageCreateSerializer(data=cdata)
if serializer.is_valid():
image = serializer.save()
else:
continue
if serializer.is_valid():
image = serializer.save()
else:
continue
if 'img' in cdata:
try:
image_object = ImageObject.objects.get(id=cdata['img'])
image_object = ImageObject.objects.get(id=cdata.get('img'))
except ImageObject.DoesNotExist:
pass
else:
@ -71,25 +59,15 @@ class DispatchContentMixin(object):
if 'id' in cdata and cdata['id']:
it = ImageText.objects.get(id=cdata.pop('id'))
serializer = ImageTextCreateSerializer(it, data=cdata)
if serializer.is_valid():
it = serializer.save()
else:
continue
try:
image_object = ImageObject.objects.get(id=cdata['img'])
except ImageObject.DoesNotExist:
pass
else:
it.img = image_object
it.save()
else:
serializer = ImageTextCreateSerializer(data=cdata)
if serializer.is_valid():
it = serializer.save()
else:
continue
if serializer.is_valid():
it = serializer.save()
else:
continue
if 'img' in cdata:
try:
image_object = ImageObject.objects.get(id=cdata['img'])
image_object = ImageObject.objects.get(id=cdata.get('img'))
except ImageObject.DoesNotExist:
pass
else:
@ -100,52 +78,36 @@ class DispatchContentMixin(object):
if 'id' in cdata and cdata['id']:
v = Video.objects.get(id=cdata.pop('id'))
serializer = VideoCreateSerializer(v, data=cdata)
if serializer.is_valid():
serializer.save()
else:
serializer = VideoCreateSerializer(data=cdata)
if serializer.is_valid():
serializer.save()
if serializer.is_valid():
serializer.save()
elif ctype == 'images':
if 'id' in cdata and cdata['id']:
g = Gallery.objects.get(id=cdata['id'])
g.position = cdata['position']
g.title = cdata['title']
g.uuid = cdata['uuid']
setattr(g, obj_type, obj)
g.save()
if 'images' in cdata:
for image in cdata['images']:
if 'img' in image and image['img']:
if 'id' in image and image['id']:
gi = GalleryImage.objects.get(id=image['id'])
gi.img = ImageObject.objects.get(id=image['img'])
gi.save()
else:
gi = GalleryImage.objects.create(
gallery=g,
img=ImageObject.objects.get(id=image['img'])
)
else:
g = Gallery(
position=cdata['position'],
title=cdata['title'],
uuid=cdata['uuid'],
)
setattr(g, obj_type, obj)
g.save()
if 'images' in cdata:
for image in cdata['images']:
if 'img' in image and image['img']:
if 'id' in image and image['id']:
gi = GalleryImage.objects.get(id=image['id'])
gi.img = ImageObject.objects.get(id=image['img'])
gi.save()
else:
gi = GalleryImage.objects.create(
gallery=g,
img=ImageObject.objects.get(id=image['img'])
)
setattr(g, obj_type, obj)
g.save()
if 'images' in cdata:
for image in cdata['images']:
if 'img' in image and image['img']:
if 'id' in image and image['id']:
gi = GalleryImage.objects.get(id=image['id'])
gi.img = ImageObject.objects.get(id=image['img'])
gi.save()
else:
gi = GalleryImage.objects.create(
gallery=g,
img=ImageObject.objects.get(id=image['img'])
)
class DispatchMaterialMixin(object):

@ -1,3 +1,5 @@
from datetime import datetime
from django.contrib.auth import get_user_model
from rest_framework import status, views, viewsets, generics
@ -566,10 +568,12 @@ class PaymentViewSet(viewsets.ModelViewSet):
user = request.query_params.get('user')
course = request.query_params.get('course')
weekdays = request.query_params.getlist('weekdays[]')
date_start = request.query_params.get('date_start')
user = user and User.objects.get(pk=user)
course = course and Course.objects.get(pk=course)
date_start = date_start and datetime.strptime(date_start, '%Y-%m-%d')
return Response(Payment.calc_amount(user=user, course=course, weekdays=weekdays))
return Response(Payment.calc_amount(user=user, course=course, date_start=date_start, weekdays=weekdays))
class ContestViewSet(ExtendedModelViewSet):

@ -111,13 +111,25 @@ class Payment(PolymorphicModel):
ordering = ('created_at',)
@classmethod
def calc_amount(cls, course_payment=None, school_payment=None, user=None, course=None, weekdays=None):
def add_months(cls, sourcedate, months=1):
result = arrow.get(sourcedate, settings.TIME_ZONE).shift(months=months)
if months == 1:
if (sourcedate.month == 2 and sourcedate.day >= 28) or (sourcedate.day == 31 and result.day <= 30) \
or (sourcedate.month == 1 and sourcedate.day >= 29 and result.day == 28):
result = result.replace(day=1, month=result.month + 1)
return result.datetime
@classmethod
def calc_amount(cls, course_payment=None, school_payment=None, user=None, course=None, date_start=None, weekdays=None):
date_start = date_start or now().date()
date_end = Payment.add_months(date_start, 1)
if course_payment:
course = course_payment.course
user = course_payment.user
if school_payment:
user = school_payment.user
weekdays = school_payment.weekdays
date_start = school_payment.date_start
discount = 0
price = 0
if course:
@ -126,8 +138,8 @@ class Payment(PolymorphicModel):
if user:
school_payments = SchoolPayment.objects.filter(
user=user,
date_start__lte=now().date(),
date_end__gte=now().date(),
date_start__lte=date_start,
date_end__gte=date_start,
add_days=False,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
@ -147,7 +159,8 @@ class Payment(PolymorphicModel):
weekday__in=weekdays,
)
if add_days:
weekdays_count = weekdays_in_date_range(now().date(), prev_school_payment.date_end)
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(
@ -163,6 +176,8 @@ class Payment(PolymorphicModel):
'price': price,
'amount': amount,
'discount': discount,
'date_start': date_start,
'date_end': date_end,
}
def calc_commission(self):

@ -27,7 +27,7 @@ from apps.course.models import Course
from apps.school.models import SchoolSchedule
from apps.payment.tasks import transaction_to_mixpanel, product_payment_to_mixpanel, transaction_to_roistat
from .models import AuthorBalance, CoursePayment, SchoolPayment
from .models import AuthorBalance, CoursePayment, SchoolPayment, Payment
logger = logging.getLogger('django')
@ -101,6 +101,8 @@ class SchoolBuyView(TemplateView):
host = str(host[0]) + '://' + str(host[1])
weekdays = set(request.GET.getlist('weekdays', []))
roistat_visit = request.COOKIES.get('roistat_visit', None)
date_start = request.GET.get('date_start')
date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d') or now().date()
if not weekdays:
messages.error(request, 'Выберите несколько дней недели.')
return redirect('school:summer-school')
@ -111,21 +113,21 @@ class SchoolBuyView(TemplateView):
return redirect('school:summer-school')
prev_school_payment = SchoolPayment.objects.filter(
user=request.user,
date_start__lte=now().date(),
date_end__gte=now().date(),
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,
],
).first() # ??? first?
).last()
add_days = bool(prev_school_payment)
if add_days:
school_payment = SchoolPayment.objects.create(
user=request.user,
weekdays=weekdays,
date_start=now().date(),
date_start=date_start,
date_end=prev_school_payment.date_end,
add_days=True,
roistat_visit=roistat_visit,
@ -138,6 +140,8 @@ class SchoolBuyView(TemplateView):
user=request.user,
weekdays=weekdays,
roistat_visit=roistat_visit,
date_start=date_start,
date_end=Payment.add_months(date_start),
)
product = Product(
f'school_{school_payment.id}',
@ -164,14 +168,6 @@ class SchoolBuyView(TemplateView):
@method_decorator(csrf_exempt, name='dispatch')
class PaymentwallCallbackView(View):
def add_months(self, sourcedate, months=1):
result = arrow.get(sourcedate, settings.TIME_ZONE).shift(months=months)
if months == 1:
if (sourcedate.month == 2 and sourcedate.day >= 28) or (sourcedate.day == 31 and result.day <= 30)\
or (sourcedate.month == 1 and sourcedate.day >= 29 and result.day == 28):
result = result.replace(day=1, month=result.month + 1)
return result.datetime
def get_request_ip(self):
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
@ -217,30 +213,6 @@ class PaymentwallCallbackView(View):
product_type_name,
)
if product_type_name == 'school':
school_payment = SchoolPayment.objects.filter(
user=payment.user,
add_days=False,
date_start__lte=now().date(),
date_end__gte=now().date(),
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
).last()
if school_payment:
if payment.add_days:
date_start = now().date()
date_end = school_payment.date_end
else:
date_start = arrow.get(school_payment.date_end, settings.TIME_ZONE).shift(days=1).datetime
date_end = self.add_months(date_start)
else:
date_start = now().date()
date_end = self.add_months(date_start)
payment.date_start = date_start
payment.date_end = date_end
if product_type_name == 'course':
properties = {
'payment_id': payment.id,

@ -1,9 +1,5 @@
<a
{% if not user.is_authenticated %}
data-popup=".js-popup-auth"
{% else %}
data-popup=".js-popup-buy"
{% endif %}
data-popup=".js-popup-buy" data-prolong="1" data-date-start="{{ prolong_date_start|date:'Y-m-d' }}"
class="casing__btn btn{% if pink %} btn_pink{% endif %}"
href="#"
>продлить</a>

@ -5,14 +5,10 @@
<div class="casing">
<div class="casing__col">
<div class="casing__subscribe">
{% if is_purchased %}
<div class="casing__msg">Подписка истекает
<span class="bold">{{ subscription_ends }}</span>
</div>
{% else %}
<div class="casing__msg">Подписка
<span class="bold">истекла</span>
</div>
{% if allow_prolong %}
{% include './prolong_btn.html' with pink=True %}
{% endif %}
</div>

@ -187,6 +187,7 @@ class SchoolView(TemplateView):
ll.school_schedule = school_schedules_dict.get(ll.date.isoweekday())
live_lessons_exists = live_lessons.exists()
live_lessons = live_lessons or None
subscription_ends = school_payment.filter(add_days=False).last().date_end if school_payment_exists else None
context.update({
'online': online,
'live_lessons': live_lessons,
@ -199,7 +200,9 @@ class SchoolView(TemplateView):
'school_schedules': school_schedules,
'school_schedules_purchased': school_schedules_purchased,
'school_purchased_future': False,
'subscription_ends': school_payment.filter(add_days=False).first().date_end if school_payment_exists else None,
'subscription_ends': subscription_ends,
'prolong_date_start': subscription_ends + timedelta(days=1),
'allow_prolong': subscription_ends - date_now <= timedelta(days=14)
})
return context

@ -1,3 +1,4 @@
from django.db.models import Func, F
from django.utils.timezone import now
from paymentwall.pingback import Pingback
@ -14,7 +15,7 @@ def baner(request):
return {'baner': Baner.objects.filter(use=True).first()}
def is_summer_school_purchased(request):
def school_purchased(request):
if request.user.is_authenticated:
n = now().date()
school_payment = SchoolPayment.objects.filter(
@ -27,5 +28,14 @@ def is_summer_school_purchased(request):
date_start__lte=n,
date_end__gte=n
)
return {'is_summer_school_purchased': school_payment.exists()}
return {'is_summer_school_purchased': False}
school_schedules_purchased = school_payment.annotate(
joined_weekdays=Func(F('weekdays'), function='unnest', )
).values_list('joined_weekdays', flat=True).distinct()
return {
'is_school_purchased': school_payment.exists(),
'school_schedules_purchased': school_schedules_purchased,
}
return {
'is_school_purchased': False,
'school_schedules_purchased': [],
}

@ -94,7 +94,7 @@ TEMPLATES = [
'context_processors': [
'project.context_processors.config',
'project.context_processors.baner',
'project.context_processors.is_summer_school_purchased',
'project.context_processors.school_purchased',
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',

@ -17,6 +17,7 @@
id: '{{ request.user.id|default:'' }}',
role: +'{{ request.user.role }}',
photo: '{% if request.user.photo %}{{ request.user.photo.url }}{% else %}{% static 'img/user_default.jpg' %}{% endif %}',
}
},
components: {}
};
</script>

@ -20,40 +20,6 @@
</div>
<div class="buy__col">
<div class="buy__list">
{% if all_school_schedules %}
{% for school_schedule in all_school_schedules %}
<label class="switch switch_lesson">
<input
class="switch__input"
type="checkbox"
data-day="{{school_schedule.weekday}}"
data-price="{{school_schedule.month_price}}"
autocomplete="off"
{% if school_schedule.weekday in school_schedules_purchased %}
disabled
{% endif %}
{% if not is_purchased %}
checked
{% endif %}>
<span class="switch__content">
<span class="switch__cell">{{ school_schedule }}</span>
{% comment %} dont delete {% endcomment %}
<span class="switch__cell"></span>
<span class="switch__cell">{{ school_schedule.title }}</span>
<span class="buy__trial-lesson switch__cell">
{% if school_schedule.weekday in school_schedules_purchased %}
Куплено
{% else %}
{% if school_schedule.trial_lesson %}
<a class="js-video-modal" data-video-url="{{ school_schedule.trial_lesson }}" href="">Пробный урок</a>
{% endif %}
{% endif %}
</span>
<span class="switch__cell">{{school_schedule.month_price}}р в мес.</span>
</span>
</label>
{% endfor %}
{% else %}
{% for school_schedule in school_schedules %}
<label class="switch switch_lesson">
<input
@ -63,6 +29,7 @@
data-price="{{school_schedule.month_price}}"
autocomplete="off"
{% if school_schedule.weekday in school_schedules_purchased %}
data-purchased="1"
disabled
{% endif %}
{% if not is_purchased %}
@ -86,7 +53,6 @@
</span>
</label>
{% endfor %}
{% endif %}
</div>
</div>
<div class="buy__col">
@ -102,6 +68,7 @@
</div>
<div class="order__info">
<div class="order__label">ШКОЛА</div>
<div class="order__dates"></div>
<div class="order__days"></div>
</div>
<div class="order__foot">

@ -316,12 +316,12 @@
</div>
</div>
{% include 'templates/blocks/lil_store_js.html' %}
<script type="text/javascript" src={% static "app.js" %}></script>
<script>
var schoolDiscount = parseFloat({{ config.SERVICE_DISCOUNT }});
var schoolAmountForDiscount = parseFloat({{ config.SERVICE_DISCOUNT_MIN_AMOUNT }});
</script>
{% block foot %}{% endblock foot %}
<script type="text/javascript" src={% static "app.js" %}></script>
</body>
</html>

@ -47,14 +47,14 @@ urlpatterns = [
path('author-request/success/', TemplateView.as_view(template_name='user/become-author-success.html'), name='author-request-success'),
path('courses/', CoursesView.as_view(), name='courses'),
path('course/create', CourseEditView.as_view(), name='course_create'),
path('course/create/lessons', CourseEditView.as_view(), name='course_create_lessons'),
path('course/create/lessons/new', CourseEditView.as_view(), name='course_create_lessons_new'),
path('course/create/lessons/edit/<int:lesson>', CourseEditView.as_view(), name='course_create_lessons_edit'),
path('course/<int:pk>/lessons/new', CourseEditView.as_view(), name='course_lessons_new'),
path('course/<int:pk>/lessons/<int:lesson>/edit', CourseEditView.as_view(), name='course_lessons_edit'),
path('course/on-moderation', CourseOnModerationView.as_view(), name='course-on-moderation'),
path('course/<int:pk>/', CourseView.as_view(), name='course'),
path('course/<str:slug>/', CourseView.as_view(), name='course'),
path('course/<int:pk>/checkout', CourseBuyView.as_view(), name='course-checkout'),
path('course/<int:pk>/edit', CourseEditView.as_view(), name='course_edit'),
path('course/<int:pk>/edit/lessons', CourseEditView.as_view(), name='course_edit_lessons'),
path('course/<int:pk>/lessons', CourseView.as_view(template_name='course/course_only_lessons.html', only_lessons=True), name='course-only-lessons'),
path('course/<int:course_id>/like', likes, name='likes'),
path('course/<int:course_id>/comment', coursecomment, name='coursecomment'),

@ -66,45 +66,7 @@
<div class="section__center center">
<div class="kit">
<div class="kit__body">
<vue-draggable v-model="contest.content" @start="drag=true" @end="drag=false" :options="{ handle: '.sortable__handle' }">
<div v-for="(block, index) in contest.content" :key="block.data.id ? block.data.id : block.data.guid">
<block-text v-if="block.type === 'text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image-text v-if="block.type === 'image-text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image v-if="block.type === 'image'"
:index="index"
:title.sync="block.data.title"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-images v-if="block.type === 'images'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:images.sync="block.data.images"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-video v-if="block.type === 'video'"
:index="index"
:title.sync="block.data.title"
v-on:remove="onBlockRemoved"
:video-url.sync="block.data.video_url"/>
</div>
</vue-draggable>
<block-add v-on:added="onBlockAdded"/>
<block-content :content.sync="contest.content"></block-content>
</div>
</div>
</div>
@ -113,15 +75,9 @@
</template>
<script>
import BlockText from './blocks/BlockText'
import BlockImage from './blocks/BlockImage'
import BlockImages from './blocks/BlockImages'
import BlockImageText from './blocks/BlockImageText'
import BlockVideo from './blocks/BlockVideo'
import BlockAdd from "./blocks/BlockAdd";
import {api} from "../js/modules/api";
import DatePicker from 'vuejs-datepicker';
import Draggable from 'vuedraggable';
import BlockContent from './blocks/BlockContent'
import slugify from 'slugify';
import {required, minValue, numeric, url } from 'vuelidate/lib/validators'
import _ from 'lodash';
@ -175,18 +131,6 @@
}
},
methods: {
onBlockRemoved(blockIndex) {
const blockToRemove = this.contest.content[blockIndex];
// Удаляем блок из Vue
this.contest.content.splice(blockIndex, 1);
// Если блок уже был записан в БД, отправляем запрос на сервер на удаление блока из БД
if (blockToRemove.data.id) {
api.removeContentBlock(blockToRemove, this.accessToken);
}
},
onBlockAdded(blockData) {
this.contest.content.push(blockData);
},
onTitleInput() {
this.$v.contest.title.$touch();
if (!this.slugChanged) {
@ -219,7 +163,7 @@
id: data.id,
title: data.title,
description: data.description,
content: api.convertContentResponse(data.content),
content: api.convertContentJson(data.content),
date_start: data.date_start,
date_end: data.date_end,
slug: data.slug,
@ -252,70 +196,7 @@
data.date_start = data.date_start ? moment(data.date_start).format('MM-DD-YYYY') : null;
data.date_end = data.date_end ? moment(data.date_end).format('MM-DD-YYYY') : null;
data.cover = this.contest.coverImageId || '';
data.content = this.contest.content.map((block, index) => {
if (block.type === 'text') {
return {
'type': 'text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'txt': block.data.text,
}
}
} else if (block.type === 'image') {
return {
'type': 'image',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
}
}
} else if (block.type === 'image-text') {
return {
'type': 'image-text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
'txt': block.data.text,
}
}
} else if (block.type === 'images') {
return {
'type': 'images',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'images': block.data.images.map((galleryImage) => {
return {
'id': galleryImage.id ? galleryImage.id : null,
'img': galleryImage.img,
}
}),
}
}
} else if (block.type === 'video') {
return {
'type': 'video',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'url': block.data.video_url,
}
}
}
});
data.content = api.convertContentJson(this.contest.content, true);
const request = this.contest.id
? api.put(`/api/v1/contests/${this.contest.id}/`, data, {
@ -343,15 +224,8 @@
}
},
components: {
BlockAdd,
BlockContent,
'vue-datepicker': DatePicker,
'block-text': BlockText,
'block-image': BlockImage,
'block-image-text': BlockImageText,
'block-images': BlockImages,
'block-video': BlockVideo,
'vue-draggable': Draggable,
}
};
</script>

@ -166,45 +166,7 @@
</button>
</div>
<div v-if="viewSection === 'course'" class="kit__body">
<vue-draggable v-model="course.content" @start="drag=true" @end="drag=false" :options="{ handle: '.sortable__handle' }">
<div v-for="(block, index) in course.content" :key="block.data.id ? block.data.id : block.data.guid">
<block-text v-if="block.type === 'text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image-text v-if="block.type === 'image-text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image v-if="block.type === 'image'"
:index="index"
:title.sync="block.data.title"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-images v-if="block.type === 'images'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:images.sync="block.data.images"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-video v-if="block.type === 'video'"
:index="index"
:title.sync="block.data.title"
v-on:remove="onBlockRemoved"
:video-url.sync="block.data.video_url"/>
</div>
</vue-draggable>
<block-add v-on:added="onBlockAdded"/>
<block-content :content.sync="course.content"></block-content>
<!--<div class="kit__foot">
<button type="submit" class="kit__submit btn btn_md" v-bind:class="{ loading: courseSaving }">
@ -236,7 +198,7 @@
</div>
<div class="lessons__subtitle subtitle">{{ lesson.title }}</div>
<div class="lessons__row">
<div class="lessons__content">{{ lesson.short_description | linebreaks }}</div>
<div class="lessons__content">{{ lesson.short_description }}</div>
</div>
</div>
</vue-draggable>
@ -269,15 +231,10 @@
import { ROLE_ADMIN, ROLE_AUTHOR } from './consts'
import LinkInput from './inputs/LinkInput'
import DatePicker from 'vuejs-datepicker'
import BlockText from './blocks/BlockText'
import BlockImage from './blocks/BlockImage'
import BlockImages from './blocks/BlockImages'
import BlockImageText from './blocks/BlockImageText'
import BlockVideo from './blocks/BlockVideo'
import BlockContent from './blocks/BlockContent'
import LilSelect from "./inputs/LilSelect";
import LessonRedactor from "./LessonRedactor";
import {api} from "../js/modules/api";
import BlockAdd from "./blocks/BlockAdd";
import $ from 'jquery';
import {required, minValue, numeric, url } from 'vuelidate/lib/validators'
import slugify from 'slugify';
@ -493,18 +450,6 @@
});
}
},
onBlockRemoved(blockIndex) {
const blockToRemove = this.course.content[blockIndex];
// Удаляем блок из Vue
this.course.content.splice(blockIndex, 1);
// Если блок уже был записан в БД, отправляем запрос на сервер на удаление блока из БД
if (blockToRemove.data.id) {
api.removeContentBlock(blockToRemove, this.accessToken);
}
},
onBlockAdded(blockData) {
this.course.content.push(blockData);
},
removeLesson(lessonIndex) {
if (!confirm('Вы действительно хотите удалить этот урок?')) {
return;
@ -518,18 +463,18 @@
},
editLesson(lessonIndex) {
this.currentLesson = this.lessons[lessonIndex];
history.push("/course/create/lessons/edit/"+this.currentLesson.id);
history.push(`/course/${this.course.id}/lessons/${this.currentLesson.id}/edit`);
this.viewSection = 'lessons-edit';
},
showCourse() {
if (this.viewSection !== 'course') {
history.push("/course/create");
history.push(this.course.id ? `/course/${this.course.id}/edit` : "/course/create");
}
this.viewSection = 'course'
},
showLessons() {
if (this.viewSection !== 'lessons') {
history.push("/course/create/lessons");
history.push(`/course/${this.course.id}/edit/lessons`);
}
this.viewSection = 'lessons';
},
@ -540,7 +485,7 @@
content: [],
};
if (this.viewSection !== 'lessons-edit') {
history.push("/course/create/lessons/new");
history.push(`/course/${this.course.id}/lessons/new`);
}
this.viewSection = 'lessons-edit';
window.scrollTo(0, 0);
@ -613,7 +558,7 @@
return req;
},
goToLessons() {
history.push("/course/create/lessons");
history.push(`/course/${this.course.id}/edit/lessons`);
this.viewSection = 'lessons';
this.$nextTick(() => {
const elementTop = $('#course-redactor__nav').position().top - 130;
@ -868,18 +813,17 @@
},
updateViewSection(location, action) {
//console.log('updateViewSection[action]', action);
if (location.pathname === '/course/create/lessons') {
if (location.pathname.match(/course\/\d+\/edit\/lessons/)) {
this.viewSection = 'lessons';
} else if (location.pathname === '/course/create') {
this.viewSection = 'course';
} else if (location.pathname === '/course/create/lessons/new') {
} else if (location.pathname.match(/course\/\d+\/lessons\/new/)){
this.viewSection = 'lessons-edit';
} else if (location.pathname.indexOf('/course/create/lessons/edit') !== -1) {
let lessonId = parseInt(location.pathname.split('/').pop());
//console.log('lessonId', lessonId, this.lessons.toString());
//console.log('lessod edit', this.lessons.find((i)=>{return i.id === lessonId}));
} else if (location.pathname.match(/course\/\d+\/lessons\/\d+\/edit/)) {
// let lessonId = parseInt(location.pathname.split('/').pop());
const lessonId = +location.pathname.match(/lessons\/(\d+)\/edit/)[1];
this.currentLesson = this.lessons.find((i)=>{return i.id === lessonId});
this.viewSection = 'lessons-edit';
} else {
this.viewSection = 'course';
}
},
onLessonsChanged() {
@ -1127,17 +1071,11 @@
},
components: {
BlockAdd,
LessonRedactor,
LilSelect,
BlockText,
BlockContent,
'link-input': LinkInput,
'vue-datepicker': DatePicker,
'block-text': BlockText,
'block-image': BlockImage,
'block-image-text': BlockImageText,
'block-images': BlockImages,
'block-video': BlockVideo,
'lesson-redactor': LessonRedactor,
'vue-draggable': Draggable,
}

@ -33,44 +33,7 @@
</div>
</div>
</div>
<vue-draggable v-model="lesson.content" @start="drag=true" @end="drag=false" :options="{ handle: '.sortable__handle' }">
<div v-for="(block, index) in lesson.content">
<block-text v-if="block.type === 'text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image-text v-if="block.type === 'image-text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-image v-if="block.type === 'image'"
:index="index"
:title.sync="block.data.title"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_url"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-images v-if="block.type === 'images'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:images.sync="block.data.images"
v-on:remove="onBlockRemoved"
:access-token="accessToken"/>
<block-video v-if="block.type === 'video'"
:index="index"
:title.sync="block.data.title"
v-on:remove="onBlockRemoved"
:video-url.sync="block.data.video_url"/>
</div>
</vue-draggable>
<block-add v-on:added="onBlockAdded" />
<block-content :content.sync="lesson.content"></block-content>
<div class="kit__foot">
<button class="kit__submit btn btn_md" v-bind:class="{ loading: saving }">Сохранить</button>
@ -81,12 +44,7 @@
</template>
<script>
import BlockAdd from "./blocks/BlockAdd";
import BlockText from './blocks/BlockText'
import BlockImage from './blocks/BlockImage'
import BlockImages from './blocks/BlockImages'
import BlockImageText from './blocks/BlockImageText'
import BlockVideo from './blocks/BlockVideo'
import BlockContent from './blocks/BlockContent'
import LilImage from "./blocks/Image"
import {api} from "../js/modules/api";
import Draggable from 'vuedraggable';
@ -99,20 +57,6 @@
goBack() {
this.$emit('back');
},
onBlockAdded(blockData) {
this.lesson.content.push(blockData);
this.$emit('update:lesson', this.lesson);
},
onBlockRemoved(blockIndex) {
const blockToRemove = this.lesson.content[blockIndex];
// Удаляем блок из Vue
this.lesson.content.splice(blockIndex, 1);
this.$emit('update:lesson', this.lesson);
// Если блок уже был записан в БД, отправляем запрос на сервер на удаление блока из БД
if (blockToRemove.data.id) {
api.removeContentBlock(blockToRemove, this.accessToken);
}
},
onUpdateCoverUrl(newValue) {
this.lesson.coverImage = newValue;
},
@ -126,13 +70,7 @@
}
},
components: {
BlockAdd,
'block-text': BlockText,
'block-image': BlockImage,
'block-image-text': BlockImageText,
'block-images': BlockImages,
'block-video': BlockVideo,
'vue-draggable': Draggable,
BlockContent,
'lil-image': LilImage,
}
}

@ -0,0 +1,87 @@
<template>
<div>
<vue-draggable :list="content" @start="drag=true" @end="drag=false" :options="{ handle: '.sortable__handle' }">
<div v-for="(block, index) in content" :key="block.id ? block.id : block.uuid">
<block-text v-if="block.type === 'text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
v-on:remove="onBlockRemoved"/>
<block-image-text v-if="block.type === 'image-text'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_thumbnail_url"
v-on:remove="onBlockRemoved"
:access-token="$root.store.accessToken"/>
<block-image v-if="block.type === 'image'"
:index="index"
:title.sync="block.data.title"
:image-id.sync="block.data.image_id"
:image-url.sync="block.data.image_thumbnail_url"
v-on:remove="onBlockRemoved"
:access-token="$root.store.accessToken"/>
<block-images v-if="block.type === 'images'"
:index="index"
:title.sync="block.data.title"
:text.sync="block.data.text"
:images.sync="block.data.images"
v-on:remove="onBlockRemoved"
:access-token="$root.store.accessToken"/>
<block-video v-if="block.type === 'video'"
:index="index"
:title.sync="block.data.title"
v-on:remove="onBlockRemoved"
:video-url.sync="block.data.video_url"/>
</div>
</vue-draggable>
<block-add v-on:added="onBlockAdded"/>
</div>
</template>
<script>
import {api} from "../../js/modules/api";
import Draggable from 'vuedraggable';
import BlockText from './BlockText'
import BlockImage from './BlockImage'
import BlockImages from './BlockImages'
import BlockImageText from './BlockImageText'
import BlockVideo from './BlockVideo'
import BlockAdd from "./BlockAdd"
export default {
name: 'block-content',
props: ['content'],
methods: {
onBlockRemoved(blockIndex) {
const content = this.content;
const blockToRemove = this.content[blockIndex];
// Если блок уже был записан в БД, отправляем запрос на сервер на удаление блока из БД
if (blockToRemove.data.id) {
api.removeContentBlock(blockToRemove, this.$root.store.accessToken).then(response => {
// Удаляем блок из Vue
content.splice(blockIndex, 1);
this.$emit('update:content', content);
});
}
},
onBlockAdded(blockData) {
const content = this.content;
content.push(blockData);
this.$emit('update:content', content);
},
},
components: {
BlockAdd,
'block-text': BlockText,
'block-image': BlockImage,
'block-image-text': BlockImageText,
'block-images': BlockImages,
'block-video': BlockVideo,
'vue-draggable': Draggable,
}
}
</script>

@ -23,7 +23,7 @@
</div>
<div class="kit__gallery">
<div class="kit__preview" v-for="(image, index) in images" v-bind:class="{ 'kit__preview--loading': image.loading }">
<img :src="image.src" class="kit__pic">
<img :src="image.image_thumbnail_url" class="kit__pic">
<button type="button" @click="onRemoveImage(index)">
<svg class="icon icon-delete">
<use xlink:href="/static/img/sprite.svg#icon-delete"></use>
@ -66,12 +66,12 @@
api.uploadImage(reader.result, this.accessToken)
.then((response) => {
let images = this.images;
console.log('images before', JSON.stringify(images));
images.forEach((image, index) => {
if (image.src === reader.result) {
images[index].img = response.data.id;
images[index].image_id = response.data.id;
images[index].loading = false;
images[index].src = response.data.image;
images[index].image_url = response.data.image;
images[index].image_thumbnail_url = response.data.image_thumbnail;
}
});
console.log('images after', JSON.stringify(images));
@ -91,12 +91,14 @@
},
onRemoveImage(index) {
let images = this.images;
let id = images[index].img;
images.splice(index, 1);
this.$emit('update:images', images);
let id = images[index].image_id;
api.removeImage(id, this.accessToken);
api.removeImage(id, this.accessToken)
.then(response => {
images.splice(index, 1);
this.$emit('update:images', images);
});
}
}
}
</script>
</script>

@ -18,6 +18,7 @@
data() {
return {
loading: false,
}
},
methods: {
@ -45,7 +46,7 @@
.then((response) => {
this.loading = false;
this.$emit('update:imageId', response.data.id);
this.$emit('update:imageUrl', response.data.image);
this.$emit('update:imageUrl', response.data.image_thumbnail);
})
.catch((error) => {
this.loading = false;

@ -25,18 +25,29 @@ import "../sass/app.sass";
import Vue from 'vue';
import Vuelidate from 'vuelidate';
import VueAutosize from '../components/directives/autosize'
import Comments from '../components/Comments';
import UploadContestWork from '../components/UploadContestWork.vue';
import ContestWorks from '../components/ContestWorks.vue';
import Likes from '../components/blocks/Likes.vue';
Vue.use(Vuelidate);
Vue.use(VueAutosize);
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
Vue.config.devtools = true;
}
const components = {
UploadContestWork,
ContestWorks,
Likes,
Comments,
};
Object.assign(components, window.LIL_STORE.components);
const app = new Vue({
el: '#lilcity-vue-app',
data() {
@ -44,10 +55,5 @@ const app = new Vue({
store: window.LIL_STORE,
}
},
components: {
UploadContestWork,
ContestWorks,
Likes,
Comments,
}
components: components
});

@ -1,19 +1,4 @@
import Vue from 'vue'
import Vuelidate from 'vuelidate'
import VueAutosize from '../components/directives/autosize'
import ContestRedactor from '../components/ContestRedactor.vue'
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
Vue.config.devtools = true;
}
window.LIL_STORE.components['contest-redactor'] = ContestRedactor;
Vue.use(VueAutosize);
Vue.use(Vuelidate);
let app = new Vue({
el: '#lilcity-vue-app',
components: {
'contest-redactor': ContestRedactor,
}
});

@ -1,24 +1,8 @@
import Vue from 'vue'
import VueAutosize from '../components/directives/autosize'
import Vuelidate from 'vuelidate'
import 'babel-polyfill'
import CourseRedactor from '../components/CourseRedactor.vue'
import $ from 'jquery';
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
Vue.config.devtools = true;
}
Vue.use(VueAutosize);
Vue.use(Vuelidate);
let app = new Vue({
el: '#lilcity-vue-app',
components: {
'course-redactor': CourseRedactor,
}
});
window.LIL_STORE.components['course-redactor'] = CourseRedactor;
$(document).ready(function () {
$('#course-redactor__publish-button').on('click', function () {
@ -29,4 +13,4 @@ $(document).ready(function () {
let event = new Event('course_preview');
document.getElementById('lilcity__course-redactor').dispatchEvent(event);
});
});
});

@ -116,72 +116,9 @@ export const api = {
stream: courseObject.stream,
cover: courseObject.coverImageId ? courseObject.coverImageId : null,
gallery: {
gallery_images: courseObject.gallery && courseObject.gallery.images ? courseObject.gallery.images : []
gallery_images: courseObject.gallery && courseObject.gallery.images || []
},
content: courseObject.content.map((block, index) => {
if (block.type === 'text') {
return {
'type': 'text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'txt': block.data.text,
}
}
} else if (block.type === 'image') {
return {
'type': 'image',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
}
}
} else if (block.type === 'image-text') {
return {
'type': 'image-text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
'txt': block.data.text,
}
}
} else if (block.type === 'images') {
return {
'type': 'images',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'images': block.data.images.map((galleryImage) => {
return {
'id': galleryImage.id ? galleryImage.id : null,
'img': galleryImage.img,
}
}),
}
}
} else if (block.type === 'video') {
return {
'type': 'video',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'url': block.data.video_url,
}
}
}
}),
content: api.convertContentJson(courseObject.content, true),
};
if(courseObject.live) {
@ -209,16 +146,70 @@ export const api = {
short_description: lessonObject.short_description,
course: lessonObject.course_id,
position: lessonObject.position,
content: lessonObject.content.map((block, index) => {
content: api.convertContentJson(lessonObject.content, true),
};
if (isAdding) {
return api.addLesson(lessonJson, accessToken);
} else {
return api.updateLesson(lessonObject.id, lessonJson, accessToken);
}
},
convertLessonJson: (lessonJSON) => {
return {
id: lessonJSON.id,
title: lessonJSON.title,
short_description: lessonJSON.short_description,
coverImageId: lessonJSON.cover && lessonJSON.cover.id ? lessonJSON.cover.id : null,
coverImage: lessonJSON.cover && lessonJSON.cover.image ? lessonJSON.cover.image : null,
content: api.convertContentJson(lessonJSON.content),
position: lessonJSON.position,
}
},
convertCourseJson: (courseJSON) => {
let isDeferred = false;
let deferredDate = false;
let deferredTime = '';
if (courseJSON.deferred_start_at) {
let deferredDateTime = moment(courseJSON.deferred_start_at);
isDeferred = true;
deferredDate = deferredDateTime.format('MM-DD-YYYY');
deferredTime = deferredDateTime.format('HH:mm');
}
return {
id: courseJSON.id,
title: courseJSON.title,
status: courseJSON.status,
short_description: courseJSON.short_description,
category: courseJSON.category && courseJSON.category.id ? courseJSON.category.id : courseJSON.category,
author: courseJSON.author && courseJSON.author.id ? courseJSON.author.id : courseJSON.author,
price: parseFloat(courseJSON.price),
is_paid: parseFloat(courseJSON.price) > 0,
is_deferred: isDeferred,
date: deferredDate || courseJSON.date,
time: deferredTime ? {title: deferredTime, value: deferredTime} : null,
duration: courseJSON.duration,
is_featured: courseJSON.is_featured,
url: courseJSON.slug,
stream: courseJSON.stream,
coverImageId: courseJSON.cover && courseJSON.cover.id ? courseJSON.cover.id : null,
coverImage: courseJSON.cover && courseJSON.cover.image ? courseJSON.cover.image : null,
content: api.convertContentJson(courseJSON.content),
gallery: {images: (courseJSON.gallery) ? courseJSON.gallery.gallery_images:[]},
}
},
convertContentJson: (contentJson, forSaving) => {
if(forSaving){
return contentJson.map((block, index) => {
if (block.type === 'text') {
return {
'type': 'text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'txt': block.data.text,
'uuid': block.uuid,
}
}
} else if (block.type === 'image') {
@ -226,10 +217,10 @@ export const api = {
'type': 'image',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
'uuid': block.uuid,
}
}
} else if (block.type === 'image-text') {
@ -237,11 +228,11 @@ export const api = {
'type': 'image-text',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'img': block.data.image_id,
'txt': block.data.text,
'uuid': block.uuid,
}
}
} else if (block.type === 'images') {
@ -249,15 +240,15 @@ export const api = {
'type': 'images',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'images': block.data.images.map((galleryImage) => {
return {
'id': galleryImage.id ? galleryImage.id : null,
'img': galleryImage.img,
'img': galleryImage.image_id,
}
}),
'uuid': block.uuid,
}
}
} else if (block.type === 'video') {
@ -265,66 +256,15 @@ export const api = {
'type': 'video',
'data': {
'id': block.data.id ? block.data.id : null,
'uuid': block.uuid,
'position': ++index,
'title': block.data.title,
'url': block.data.video_url,
'uuid': block.uuid,
}
}
}
}),
};
if (isAdding) {
return api.addLesson(lessonJson, accessToken);
} else {
return api.updateLesson(lessonObject.id, lessonJson, accessToken);
});
}
},
convertLessonJson: (lessonJSON) => {
return {
id: lessonJSON.id,
title: lessonJSON.title,
short_description: lessonJSON.short_description,
coverImageId: lessonJSON.cover && lessonJSON.cover.id ? lessonJSON.cover.id : null,
coverImage: lessonJSON.cover && lessonJSON.cover.image ? lessonJSON.cover.image : null,
content: api.convertContentResponse(lessonJSON.content),
position: lessonJSON.position,
}
},
convertCourseJson: (courseJSON) => {
let isDeferred = false;
let deferredDate = false;
let deferredTime = '';
if (courseJSON.deferred_start_at) {
let deferredDateTime = moment(courseJSON.deferred_start_at);
isDeferred = true;
deferredDate = deferredDateTime.format('MM-DD-YYYY');
deferredTime = deferredDateTime.format('HH:mm');
}
return {
id: courseJSON.id,
title: courseJSON.title,
status: courseJSON.status,
short_description: courseJSON.short_description,
category: courseJSON.category && courseJSON.category.id ? courseJSON.category.id : courseJSON.category,
author: courseJSON.author && courseJSON.author.id ? courseJSON.author.id : courseJSON.author,
price: parseFloat(courseJSON.price),
is_paid: parseFloat(courseJSON.price) > 0,
is_deferred: isDeferred,
date: deferredDate || courseJSON.date,
time: deferredTime ? {title: deferredTime, value: deferredTime} : null,
duration: courseJSON.duration,
is_featured: courseJSON.is_featured,
url: courseJSON.slug,
stream: courseJSON.stream,
coverImageId: courseJSON.cover && courseJSON.cover.id ? courseJSON.cover.id : null,
coverImage: courseJSON.cover && courseJSON.cover.image ? courseJSON.cover.image : null,
content: api.convertContentResponse(courseJSON.content),
gallery: {images: (courseJSON.gallery) ? courseJSON.gallery.gallery_images:[]},
}
},
convertContentResponse: (contentJson) => {
return contentJson.sort((a, b) => {
if (a.position < b.position) {
return -1;
@ -353,6 +293,7 @@ export const api = {
'title': contentItem.title,
'image_id': (contentItem.img) ? contentItem.img.id:null,
'image_url': (contentItem.img) ? contentItem.img.image:null,
'image_thumbnail_url': (contentItem.img) ? contentItem.img.image_thumbnail:null,
}
}
} else if (contentItem.type === 'image-text') {
@ -364,6 +305,7 @@ export const api = {
'title': contentItem.title,
'image_id': (contentItem.img) ? contentItem.img.id:null,
'image_url': (contentItem.img) ? contentItem.img.image:null,
'image_thumbnail_url': (contentItem.img) ? contentItem.img.image_thumbnail:null,
'text': contentItem.txt,
}
}
@ -377,8 +319,9 @@ export const api = {
'images': contentItem.gallery_images.map((galleryImage) => {
return {
'id': galleryImage.id,
'img': galleryImage.img.id,
'src': galleryImage.img.image,
'image_id': galleryImage.img.id,
'image_url': galleryImage.img.image,
'image_thumbnail_url': galleryImage.img.image_thumbnail,
}
}),
}

@ -1,59 +0,0 @@
import Vue from 'vue';
import Comments from '../../components/Comments';
//import $ from 'jquery';
if (process.env.NODE_ENV === 'development') {
// Enable vue-devtools
Vue.config.devtools = true;
}
let app = new Vue({
el: '#comments_block',
data(){
return {
userId: 123,
accessToken: 123,
comments: [{
author: {
get_full_name: 'John Doe',
photo: {url: ''},
},
created_at_humanize: '12 07 18',
content: 'content content content content',
id: 1,
is_child_node: false
}, {
author: {
get_full_name: 'Sarah Conor',
photo: {url: ''},
},
created_at_humanize: '5 05 18',
content: 'hasta la vista',
id: 2,
is_child_node: false,
children: [{
author: {
get_full_name: 'John Doe',
photo: {url: ''},
},
created_at_humanize: '12 07 18',
content: 'content content content content',
id: 10,
is_child_node: true
}, {
author: {
get_full_name: 'Sarah Conor',
photo: {url: ''},
},
created_at_humanize: '5 05 18',
content: 'hasta la vista',
id: 20,
is_child_node: true,
}]
}]
}
},
components: {
'comments': Comments,
}
});

@ -1,6 +1,9 @@
import $ from 'jquery';
import moment from 'moment';
import {api} from './api';
moment.locale('ru');
var selectedWeekdays = {};
$(document).ready(function () {
$(".js-video-modal").each(function(){
@ -46,21 +49,12 @@ $(document).ready(function () {
popup = $(data);
showPopup();
let is_extend = false;
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);
if ($this.text() === 'продлить') {
//data-purchased
//restore purchased selection
console.log('restore purchased');
$('[data-purchased]').each(function(){
$('[data-day='+$(this).data('purchased')+']').prop('checked', true);
});
is_extend = true;
}
if(! window.LIL_STORE.user.id) {
const $btn = popup.find('.buy__btn');
$btn.click(function(event) {
@ -72,7 +66,30 @@ $(document).ready(function () {
});
});
}
if ($this.data('prolong')) {
$('[data-day][data-purchased]').each(function(){
$(this).prop('checked', true).prop('disabled', false);
});
}
else{
if($this.data('day')) {
let day = $this.data('day');
$('[data-day][data-purchased]').each(function(){
$(this).prop('checked', false).prop('disabled', true);
});
$('[data-day='+day+']').prop('checked', true);
}
else{
$('[data-day]').each(function(){
$(this).prop('checked', true).prop('disabled', false);
});
}
}
updateCart();
}
if( data === '.js-popup-auth') {
let nextUrl = $this.data('auth-next-url');
if(nextUrl === 'href') {
@ -80,20 +97,6 @@ $(document).ready(function () {
}
popup.data('next-url', nextUrl);
}
if($this.data('day')) {
let day = $this.data('day');
$('[data-day='+day+']').prop('checked', true);
}
if(!is_extend && !$this.data('day')) {
console.log('check all');
$('[data-day]').each(function(){
$(this).prop('checked', true);
});
}
updateCart();
});
$('.js-popup-close').on('click', function(e){
@ -147,7 +150,10 @@ $(document).ready(function () {
});
function updateCart(){
var link = $('.but_btn_popup').data('link');
var $orderPrice = $('.order_price_text');
var $orderDates = $('.order__dates');
var dateStart = popup.data('date-start');
var days = ['', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'];
var weekdays = [];
var daysText = [];
@ -160,7 +166,7 @@ $(document).ready(function () {
});
if(weekdays.length){
api.getPaymentAmount({ user: window.LIL_STORE.user.id, weekdays: weekdays })
api.getPaymentAmount({ user: window.LIL_STORE.user.id, weekdays: weekdays, date_start: dateStart})
.then((response) => {
var text = '';
if(response.data.price != response.data.amount) {
@ -169,16 +175,16 @@ $(document).ready(function () {
text = response.data.amount+'p.';
}
$orderPrice.html(text);
$orderDates.text(moment(response.data.date_start).format('D MMM') + ' - ' + moment(response.data.date_end).format('D MMM'));
$('.but_btn_popup').attr('href', link+'?'+decodeURIComponent($.param({
weekdays: weekdays,
date_start: moment(response.data.date_start).format('YYYY-MM-DD')
}, true)));
});
}
else {
$orderPrice.html('0p.');
}
$('.order__days').html(daysText.length ? daysText.join(', ') : 'Ничего не выбрано');
var link = $('.but_btn_popup').data('link');
link = link+'?'+decodeURIComponent($.param({weekdays: weekdays}, true));
$('.but_btn_popup').attr('href', link);
}
});

Loading…
Cancel
Save