Skip to content

Commit

Permalink
Merge pull request #221 from mitodl/ahmedbelal/146-product-page-facul…
Browse files Browse the repository at this point in the history
…ty-carousel

#146 Product Page: Faculty Carousel
  • Loading branch information
ahmed-arbisoft committed May 14, 2019
2 parents ff614d9 + 230c17f commit 066edb0
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 3 deletions.
14 changes: 14 additions & 0 deletions cms/blocks.py
Expand Up @@ -41,3 +41,17 @@ class UserTestimonialBlock(blocks.StructBlock):
blank=True, null=True, help_text="The image to display on the testimonial"
)
quote = blocks.TextBlock(help_text="The quote that appears on the testimonial.")


class FacultyBlock(blocks.StructBlock):
"""
Block class that defines a faculty member
"""

name = blocks.CharBlock(max_length=100, help_text="Name of the faculty member.")
image = ImageChooserBlock(
help_text="Profile image size must be at least 300x300 pixels."
)
description = blocks.RichTextBlock(
help_text="A brief description about the faculty member."
)
30 changes: 29 additions & 1 deletion cms/factories.py
Expand Up @@ -15,8 +15,14 @@
CoursesInProgramPage,
ResourcePage,
UserTestimonialsPage,
FacultyMembersPage,
)
from cms.blocks import (
LearningTechniqueBlock,
ResourceBlock,
UserTestimonialBlock,
FacultyBlock,
)
from cms.blocks import LearningTechniqueBlock, ResourceBlock, UserTestimonialBlock
from courses.factories import ProgramFactory, CourseFactory


Expand Down Expand Up @@ -170,3 +176,25 @@ class UserTestimonialsPageFactory(wagtail_factories.PageFactory):

class Meta:
model = UserTestimonialsPage


class FacultyBlockFactory(wagtail_factories.StructBlockFactory):
"""FacultyBlock factory class"""

name = factory.fuzzy.FuzzyText(prefix="faculty ")
image = factory.SubFactory(wagtail_factories.ImageFactory)
description = factory.fuzzy.FuzzyText(prefix="description ")

class Meta:
model = FacultyBlock


class FacultyMembersPageFactory(wagtail_factories.PageFactory):
"""FacultyMembersPage factory class"""

heading = factory.fuzzy.FuzzyText(prefix="heading ")
subhead = factory.fuzzy.FuzzyText(prefix="subhead ")
members = wagtail_factories.StreamFieldFactory(FacultyBlockFactory)

class Meta:
model = FacultyMembersPage
84 changes: 84 additions & 0 deletions cms/migrations/0016_faculty_members_subpage.py
@@ -0,0 +1,84 @@
# Generated by Django 2.1.7 on 2019-05-06 15:25

from django.db import migrations, models
import django.db.models.deletion
import wagtail.core.blocks
import wagtail.core.fields
import wagtail.images.blocks


class Migration(migrations.Migration):

dependencies = [
("wagtailcore", "0041_group_collection_permissions_verbose_name_plural"),
("cms", "0015_user_testimonials_subpage"),
]

operations = [
migrations.CreateModel(
name="FacultyMembersPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.Page",
),
),
(
"heading",
models.CharField(
help_text="The heading to display for this section on the product page.",
max_length=255,
),
),
(
"subhead",
models.CharField(
help_text="The subhead to display for this section on the product page.",
max_length=255,
),
),
(
"members",
wagtail.core.fields.StreamField(
[
(
"member",
wagtail.core.blocks.StructBlock(
[
(
"name",
wagtail.core.blocks.CharBlock(
help_text="Name of the faculty member.",
max_length=100,
),
),
(
"image",
wagtail.images.blocks.ImageChooserBlock(
help_text="Profile image size must be at least 300x300 pixels."
),
),
(
"description",
wagtail.core.blocks.RichTextBlock(
help_text="A brief description about the faculty member."
),
),
]
),
)
],
help_text="The faculty members to display on this page",
),
),
],
options={"abstract": False},
bases=("wagtailcore.page",),
)
]
32 changes: 31 additions & 1 deletion cms/models.py
Expand Up @@ -22,7 +22,12 @@
from modelcluster.fields import ParentalKey

from mitxpro.views import get_js_settings_context
from .blocks import LearningTechniqueBlock, ResourceBlock, UserTestimonialBlock
from cms.blocks import (
LearningTechniqueBlock,
ResourceBlock,
UserTestimonialBlock,
FacultyBlock,
)


class CourseProgramChildPage(Page):
Expand Down Expand Up @@ -215,6 +220,30 @@ class CoursesInProgramPage(CourseProgramChildPage):
content_panels = [FieldPanel("heading"), FieldPanel("body")]


class FacultyMembersPage(CourseProgramChildPage):
"""
FacultyMembersPage representing a "Your MIT Faculty" section on a product page
"""

heading = models.CharField(
max_length=255,
help_text="The heading to display for this section on the product page.",
)
subhead = models.CharField(
max_length=255,
help_text="The subhead to display for this section on the product page.",
)
members = StreamField(
[("member", FacultyBlock())],
help_text="The faculty members to display on this page",
)
content_panels = [
FieldPanel("heading"),
FieldPanel("subhead"),
StreamFieldPanel("members"),
]


class ProductPage(Page):
"""
Abstract product page
Expand Down Expand Up @@ -297,6 +326,7 @@ class Meta:
"WhoShouldEnrollPage",
"CoursesInProgramPage",
"UserTestimonialsPage",
"FacultyMembersPage",
]

def get_context(self, request, *args, **kwargs):
Expand Down
6 changes: 6 additions & 0 deletions courses/models.py
Expand Up @@ -15,6 +15,7 @@
WhoShouldEnrollPage,
CoursesInProgramPage,
UserTestimonialsPage,
FacultyMembersPage,
)
from courses.constants import (
CATALOG_COURSE_IMG_WAGTAIL_FILL,
Expand Down Expand Up @@ -167,6 +168,11 @@ def techniques(self):
"""Gets the learning techniques from the associated Page children if it exists"""
return self._get_child_page_of_type(LearningTechniquesPage)

@property
def faculty(self):
"""Gets the faculty members from the associated child page if it exists"""
return self._get_child_page_of_type(FacultyMembersPage)

@property
def faqs(self):
"""Gets the faqs related to product if exists."""
Expand Down
52 changes: 52 additions & 0 deletions courses/models_test.py
Expand Up @@ -18,6 +18,7 @@
WhoShouldEnrollPageFactory,
CoursesInProgramPageFactory,
UserTestimonialsPageFactory,
FacultyMembersPageFactory,
)

from cms.models import (
Expand Down Expand Up @@ -206,6 +207,20 @@ def test_program_learning_techniques():
assert technique.value.get("image").title == "image-title"


def test_program_faculty_subpage():
"""
FacultyMembersPage should return expected values if associated with program
"""
program = ProgramFactory.create()
program_page = ProgramPageFactory.create(program=program)

assert not program.faculty
FacultyMembersPageFactory.create(
parent=program_page, members=json.dumps(_get_faculty_members())
)
_assert_faculty_members(program)


def test_courseware_url(settings):
"""Test that the courseware_url property yields the correct values"""
settings.OPENEDX_BASE_REDIRECT_URL = "http://example.com"
Expand Down Expand Up @@ -557,3 +572,40 @@ def test_program_testimonials():
assert testimonial.value.get("title") == "title"
assert testimonial.value.get("image").title == "image"
assert testimonial.value.get("quote") == "quote"


def test_course_faculty_subpage():
"""
FacultyMembersPage should return expected values if associated with course
"""
course = CourseFactory.create()
course_page = CoursePageFactory.create(course=course)

assert not course.faculty
FacultyMembersPageFactory.create(
parent=course_page, members=json.dumps(_get_faculty_members())
)
_assert_faculty_members(course)


def _get_faculty_members():
"""Provides a `faculty` property instantiation data"""
return [
{
"type": "member",
"value": {"name": "Test Faculty", "description": "<p>description</p>"},
},
{
"type": "member",
"value": {"name": "Test Faculty", "description": "<p>description</p>"},
},
]


def _assert_faculty_members(obj):
"""Verifies `faculty` property returns expected value"""
assert obj.faculty
for block in obj.faculty.members:
assert block.block_type == "member"
assert block.value["name"] == "Test Faculty"
assert block.value["description"].source == "<p>description</p>"
2 changes: 1 addition & 1 deletion courses/templates/course_detail.html
Expand Up @@ -32,11 +32,11 @@
{% if course.who_should_enroll %} {% include "partials/target-audience.html" %} {% endif %}
{% if course.techniques %} {% include "partials/learning-techniques.html" %} {% endif %}
{% if course.testimonials %} {% include "partials/testimonial-carousel.html" with testimonials=course.testimonials %} {% endif %}
{% if course.faculty %} {% include "partials/faculty-carousel.html" %} {% endif %}
{% if course.program and course.program.course_lineup %}
{% include "partials/course-carousel.html" with program=course.program %}
{% endif %}
{% if course.for_teams %} {% include "partials/for-teams.html" %} {% endif %}
{% if course.faqs %} {% include "partials/faqs.html" %} {% endif %}

</div>
{% endblock %}
23 changes: 23 additions & 0 deletions courses/templates/partials/faculty-carousel.html
@@ -0,0 +1,23 @@
{% load wagtailimages_tags %}
<div class="faculty-block">
<div class="container">
<div class="head">
<h1 class="text-uppercase">{{ course.faculty.heading }}</h1>
<h3>{{ course.faculty.subhead }}</h3>
</div>
<div class="faculty-slider">
{% for member in course.faculty.members %}
<div class="slide">
<div class="slide-holder">
{% image member.value.image fill-300x300 as faculty_image %}
<img src="{{ faculty_image.url }}" alt="{{ member.value.name }}">
<h2>{{ member.value.name }}</h2>
<div class="text-holder">
{{ member.value.description|safe }}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
Binary file added static/images/faculty-bg.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions static/js/course_detail.js
Expand Up @@ -42,6 +42,40 @@ $(".course-slider").slick({
]
});

$(".faculty-slider").slick({
slidesToShow: 3,
slidesToScroll: 1,
dots: true,
infinite: true,
autoplay: false,
autoplaySpeed: 2000,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
infinite: true,
dots: true
}
},
{
breakpoint: 992,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
});

$(".learners-slider").slick({
slidesToShow: 3,
slidesToScroll: 1,
Expand Down

0 comments on commit 066edb0

Please sign in to comment.