import PropTypes from 'prop-types'; import React, {Fragment} from 'react'; import classNames from 'classnames'; import {FormattedMessage} from 'react-intl'; import Draggable from 'react-draggable'; import styles from './card.css'; import shrinkIcon from './icon--shrink.svg'; import expandIcon from './icon--expand.svg'; import rightArrow from './icon--next.svg'; import leftArrow from './icon--prev.svg'; import helpIcon from '../../lib/assets/icon--tutorials.svg'; import closeIcon from './icon--close.svg'; import {translateVideo} from '../../lib/libraries/decks/translate-video.js'; import {translateImage} from '../../lib/libraries/decks/translate-image.js'; const CardHeader = ({onCloseCards, onShrinkExpandCards, onShowAll, totalSteps, step, expanded}) => (
{totalSteps > 1 ? (
{Array(totalSteps).fill(0) .map((_, i) => (
))}
) : null}
{expanded ? : }
); class VideoStep extends React.Component { componentDidMount () { const script = document.createElement('script'); script.src = `https://fast.wistia.com/embed/medias/${this.props.video}.jsonp`; script.async = true; script.setAttribute('id', 'wistia-video-content'); document.body.appendChild(script); const script2 = document.createElement('script'); script2.src = 'https://fast.wistia.com/assets/external/E-v1.js'; script2.async = true; script2.setAttribute('id', 'wistia-video-api'); document.body.appendChild(script2); } // We use the Wistia API here to update or pause the video dynamically: // https://wistia.com/support/developers/player-api componentDidUpdate (prevProps) { // Ensure the wistia API is loaded and available if (!(window.Wistia && window.Wistia.api)) return; // Get a handle on the currently loaded video const video = window.Wistia.api(prevProps.video); // Reset the video source if a new video has been chosen from the library if (prevProps.video !== this.props.video) { video.replaceWith(this.props.video); } // Pause the video if the modal is being shrunken if (!this.props.expanded) { video.pause(); } } componentWillUnmount () { const script = document.getElementById('wistia-video-content'); script.parentNode.removeChild(script); const script2 = document.getElementById('wistia-video-api'); script2.parentNode.removeChild(script2); } render () { return (
 
); } } VideoStep.propTypes = { expanded: PropTypes.bool.isRequired, video: PropTypes.string.isRequired }; const ImageStep = ({title, image}) => (
{title}
); ImageStep.propTypes = { image: PropTypes.string.isRequired, title: PropTypes.node.isRequired }; const NextPrevButtons = ({isRtl, onNextStep, onPrevStep, expanded}) => ( {onNextStep ? (
) : null} {onPrevStep ? (
) : null} ); NextPrevButtons.propTypes = { expanded: PropTypes.bool.isRequired, isRtl: PropTypes.bool, onNextStep: PropTypes.func, onPrevStep: PropTypes.func }; CardHeader.propTypes = { expanded: PropTypes.bool.isRequired, onCloseCards: PropTypes.func.isRequired, onShowAll: PropTypes.func.isRequired, onShrinkExpandCards: PropTypes.func.isRequired, step: PropTypes.number, totalSteps: PropTypes.number }; const PreviewsStep = ({deckIds, content, onActivateDeckFactory, onShowAll}) => (
{deckIds.slice(0, 2).map(id => (
{content[id].name}
))}
); PreviewsStep.propTypes = { content: PropTypes.shape({ id: PropTypes.shape({ name: PropTypes.node.isRequired, img: PropTypes.string.isRequired, steps: PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.node, image: PropTypes.string, video: PropTypes.string, deckIds: PropTypes.arrayOf(PropTypes.string) })) }) }).isRequired, deckIds: PropTypes.arrayOf(PropTypes.string).isRequired, onActivateDeckFactory: PropTypes.func.isRequired, onShowAll: PropTypes.func.isRequired }; const Cards = props => { const { activeDeckId, content, dragging, isRtl, locale, onActivateDeckFactory, onCloseCards, onShrinkExpandCards, onDrag, onStartDrag, onEndDrag, onShowAll, onNextStep, onPrevStep, showVideos, step, expanded, ...posProps } = props; let {x, y} = posProps; if (activeDeckId === null) return; // Tutorial cards need to calculate their own dragging bounds // to allow for dragging the cards off the left, right and bottom // edges of the workspace. const cardHorizontalDragOffset = 400; // ~80% of card width const cardVerticalDragOffset = expanded ? 257 : 0; // ~80% of card height, if expanded const menuBarHeight = 48; // TODO: get pre-calculated from elsewhere? const wideCardWidth = 500; if (x === 0 && y === 0) { // initialize positions x = isRtl ? (-190 - wideCardWidth - cardHorizontalDragOffset) : 292; x += cardHorizontalDragOffset; // The tallest cards are about 320px high, and the default position is pinned // to near the bottom of the blocks palette to allow room to work above. const tallCardHeight = 320; const bottomMargin = 60; // To avoid overlapping the backpack region y = window.innerHeight - tallCardHeight - bottomMargin - menuBarHeight; } const steps = content[activeDeckId].steps; return ( // Custom overlay to act as the bounding parent for the draggable, using values from above
{steps[step].deckIds ? ( ) : ( steps[step].video ? ( showVideos ? ( ) : ( // Else show the deck image and title ) ) : ( ) )} {steps[step].trackingPixel && steps[step].trackingPixel}
0 ? onPrevStep : null} />
); }; Cards.propTypes = { activeDeckId: PropTypes.string.isRequired, content: PropTypes.shape({ id: PropTypes.shape({ name: PropTypes.node.isRequired, img: PropTypes.string.isRequired, steps: PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.node, image: PropTypes.string, video: PropTypes.string, deckIds: PropTypes.arrayOf(PropTypes.string) })) }) }), dragging: PropTypes.bool.isRequired, expanded: PropTypes.bool.isRequired, isRtl: PropTypes.bool.isRequired, locale: PropTypes.string.isRequired, onActivateDeckFactory: PropTypes.func.isRequired, onCloseCards: PropTypes.func.isRequired, onDrag: PropTypes.func, onEndDrag: PropTypes.func, onNextStep: PropTypes.func.isRequired, onPrevStep: PropTypes.func.isRequired, onShowAll: PropTypes.func, onShrinkExpandCards: PropTypes.func.isRequired, onStartDrag: PropTypes.func, showVideos: PropTypes.bool, step: PropTypes.number.isRequired, x: PropTypes.number, y: PropTypes.number }; Cards.defaultProps = { showVideos: true }; export { Cards as default, // Others exported for testability ImageStep, VideoStep };