From 3218f64326aa8962ec604391c1cb639415b64828 Mon Sep 17 00:00:00 2001 From: jaebradley Date: Fri, 12 Jan 2018 16:17:20 -0500 Subject: [PATCH] implement upsell modal update css updated css make modal experimental add waffle flag --- .../js/components/ExperimentalCarousel.jsx | 123 +++++ .../js/components/UpsellExperimentModal.jsx | 76 +++ lms/envs/common.py | 1 + lms/static/sass/_experiments.scss | 436 ++++++++++++++++++ lms/static/sass/bootstrap/lms-main.scss | 3 + .../course-home-fragment.html | 14 + package-lock.json | 42 ++ package.json | 2 + webpack.common.config.js | 1 + 9 files changed, 698 insertions(+) create mode 100644 common/static/common/js/components/ExperimentalCarousel.jsx create mode 100644 common/static/common/js/components/UpsellExperimentModal.jsx diff --git a/common/static/common/js/components/ExperimentalCarousel.jsx b/common/static/common/js/components/ExperimentalCarousel.jsx new file mode 100644 index 0000000000..93d1181d6c --- /dev/null +++ b/common/static/common/js/components/ExperimentalCarousel.jsx @@ -0,0 +1,123 @@ +import React from 'react'; +import Slider from 'react-slick'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; + +/** Experimental Carousel as part of https://openedx.atlassian.net/browse/LEARNER-3583 **/ + +function NextArrow(props) { + const {currentSlide, slideCount, onClick, displayedSlides} = props; + const showArrow = slideCount - currentSlide > displayedSlides; + const opts = { + className: classNames('js-carousel-nav', 'carousel-arrow', 'next', 'btn btn-secondary', {'active': showArrow}), + onClick + }; + + if (!showArrow) { + opts.disabled = 'disabled'; + } + + return ( + + ); +} + +function PrevArrow(props) { + const {currentSlide, onClick} = props; + const showArrow = currentSlide > 0; + const opts = { + className: classNames('js-carousel-nav', 'carousel-arrow', 'prev', 'btn btn-secondary', {'active': showArrow}), + onClick + }; + + if (!showArrow) { + opts.disabled = 'disabled'; + } + + return ( + + ); +} + +export default class ExperimentalCarousel extends React.Component { + constructor(props) { + super(props); + + this.state = { + // Default to undefined to not focus on page load + activeIndex: undefined, + }; + + this.carousels = []; + + this.afterChange = this.afterChange.bind(this); + this.getCarouselContent = this.getCarouselContent.bind(this); + } + + afterChange(activeIndex) { + this.setState({ activeIndex }); + } + + componentDidUpdate() { + const { activeIndex } = this.state; + + if (!isNaN(activeIndex)) { + this.carousels[activeIndex].focus(); + } + } + + getCarouselContent() { + return this.props.slides.map((slide, i) => { + const firstIndex = this.state.activeIndex || 0; + const lastIndex = firstIndex + this.props.slides.length; + const tabIndex = (firstIndex <= i && i < lastIndex) ? undefined : '-1'; + const carouselLinkProps = { + ref: (item) => { + this.carousels[i] = item; + }, + tabIndex: tabIndex, + className: 'carousel-item' + } + + return ( +
+ { slide } +
+ ); + }); + } + + render() { + const carouselSettings = { + accessibility: true, + dots: true, + infinite: false, + speed: 500, + className: 'carousel-wrapper', + nextArrow: , + prevArrow: , + afterChange: this.afterChange, + slidesToShow: 1, + slidesToScroll: 1, + initialSlide: 0, + }; + + return ( + + {this.getCarouselContent()} + + ); + } +} + +ExperimentalCarousel.propTypes = { + slides: PropTypes.array.isRequired +}; \ No newline at end of file diff --git a/common/static/common/js/components/UpsellExperimentModal.jsx b/common/static/common/js/components/UpsellExperimentModal.jsx new file mode 100644 index 0000000000..57f01a4338 --- /dev/null +++ b/common/static/common/js/components/UpsellExperimentModal.jsx @@ -0,0 +1,76 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Modal, Button } from '@edx/paragon/static'; + +import ExperimentalCarousel from './ExperimentalCarousel.jsx'; + +// https://openedx.atlassian.net/browse/LEARNER-3583 + +export class UpsellExperimentModal extends React.Component { + constructor(props) { + super(props); + + this.state = { + isOpen: true, + } + } + + render() { + const slides = [ + (
+
My Stats introduces new personalized views that help you track your progress towards completing your course!
+
With My Stats you will see your:
+
    +
  • Course Activity Streak (log in every week to keep your streak alive)
  • +
  • Grade Progress (see how you're tracking towards a passing grade)
  • +
  • Discussion Forum Engagements (top learners use the forums - how do you measure up?)
  • +
+
), + (
+
Course Activity Streak
+ Did you know the learners most likely to complete a course log in every week? Let us help you track your weekly streak - log in every week and learn something new! You can also see how many of the other learners in your course logged in this week. +
), + (
+
Grade Progress
+ Wonder how you're doing in the course so far? We can not only show you all your grades, and how much each assignment is worth, but also upcoming graded assignments. This is a great way to track what you might need to work on for a final exam. +
), + (
+
Discussion engagements
+ A large percentage of successful learners are engaged on the discussion forums. Compare your forum stats to previous graduates! +
), + ]; + const body = ( +
+ + +
+ ); + const { buttonDestinationURL } = this.props; + return ( + {}} + body={body} + buttons={[ + (