// args: user, tutor, onHide // TutorProfileModal will automatically modal when a tutor is set. // But, this means the parent must unset the tutor prop in onHide, // or complete remove the component. If the parent fails do one of these // then the parent will have no way to 're-modal' this with the same tutor // because no life cycle hooks will be called on this class. Get it? 'use strict'; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _get = function get(_x3, _x4, _x5) { var _again = true; _function: while (_again) { var object = _x3, property = _x4, receiver = _x5; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x3 = parent; _x4 = property; _x5 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var TutorProfileModal = ReactRedux.connect(function (state) { return { hiddenTutors: state.hiddenTutors, onlineStatus: state.tutorStatuses, reserveSessionModal: state.view.reserveSession }; })(React.createClass({ getInitialState: function getInitialState() { // TODO(gar): allow for loading the modal by tutorId/tutorName return { notify: false, localizedAttributes: [], tutorVideoUrl: null, snippet: "" }; }, componentWillMount: function componentWillMount() { if (!this.props.hiddenTutors.lastFetch) { fetchHiddenTutors(); } unsetTutorVideoModal(); // all students can choose to be notified when a tutor comes online this.getNotifyTutorOnline = CAMBLY.getNotifyTutorOnline().done((function (data) { for (var i = 0; i < data.tutorNotifications.length; i++) { if (data.tutorNotifications[i].tutor == this.props.tutor.userId) { this.setState({ notify: data.tutorNotifications[i].enable }); } } }).bind(this)); // Get localized attributes and tutor video CAMBLY.get('/lookupTutor', { username: this.props.tutor.username }).done((function (resp) { this.setState({ localizedAttributes: resp.tutor.localizedAttributes, tutorVideoUrl: resp.tutor.publicVideoURL, snippet: resp.tutor.snippet }); }).bind(this)); }, componentDidUpdate: function componentDidUpdate() { $(document.body).addClass('modal-open'); }, onModal: function onModal(modal) { this.modal = modal; if (modal) { $(modal).modal('show'); $(modal).on('hidden.bs.modal', (function (e) { store.dispatch(hideModal('tutorProfile')); }).bind(this)); } }, onSectionUpdate: function onSectionUpdate() { if (this.modal) { $(this.modal).resize(); } }, toggleNotifyTutorOnline: function toggleNotifyTutorOnline(e) { var checked = this.refs.notify.checked; this.setState({ notify: checked }); CAMBLY_CLIENT.toggleNotifyTutorOnline(this.props.tutor.userId, checked); }, toggleHideTutor: function toggleHideTutor() { var _this = this; this.setState({ hidingInProgress: true }); if (this.props.hiddenTutors.ids.has(this.props.tutor.userId)) { unhideTutor(this.props.tutor.userId).always(function () { return _this.setState({ hidingInProgress: false }); }); } else { hideTutor(this.props.tutor.userId).always(function () { return _this.setState({ hidingInProgress: false }); }); } }, dismiss: function dismiss() { $(this.modal).modal('hide'); store.dispatch(hideModal('tutorProfile')); }, render: function render() { var _this2 = this; var _props = this.props; var language = _props.language; var user = _props.user; var tutor = _props.tutor; var hiddenTutors = _props.hiddenTutors; if (!tutor) { return null; } var tutorStatus = this.props.onlineStatus.get(this.props.tutor.userId) || 'offline'; var practiceButton = null; if (tutorStatus == 'available' || tutorStatus == 'busy') { practiceButton = React.createElement("div", { className: "col-xs-8 col-xs-offset-2 col-sm-3 col-sm-offset-3" }, React.createElement(PracticeButton, { className: "btn-block", longText: true, language: this.props.language, user: this.props.user, tutor: this.props.tutor, status: this.props.tutorStatus })); } var messageButtonClass = classNames("col-xs-8", "col-xs-offset-2", { "col-sm-3": practiceButton, "col-sm-offset-0": practiceButton }); var messageButton = React.createElement("div", { className: messageButtonClass }, React.createElement(MessageButton, { className: "btn-block", language: language, user: user, recipient: tutor, onClick: this.dismiss })); return React.createElement("div", null, React.createElement("div", { className: "modal fade", tabIndex: "-1", role: "dialog", 'aria-labelledby': "tutorUsername", 'aria-hidden': "true", ref: this.onModal }, React.createElement("div", { className: "modal-dialog" }, React.createElement("div", { className: "modal-content" }, React.createElement("div", { className: 'card bg-texture-gray ' + (cambly.RTL ? 'text-right' : 'text-left') }, React.createElement("div", { className: "row", style: { display: 'flex' } }, React.createElement("div", { className: "col-xs-4 col-sm-3" }, React.createElement("img", { src: tutor.avatarDynamicUrl || '/static/images/silhouette.png', className: "img-fill card-top-left" })), React.createElement("div", { className: "col-xs-6 col-sm-8", style: { display: 'flex', flexFlow: 'column nowrap', justifyContent: 'center' } }, React.createElement("div", { style: { display: "flex", alignItems: "center" } }, React.createElement("div", { style: { display: "inline" } }, React.createElement("h1", { id: "tutorUsername", className: "display-3 single-line tutor-name" }, tutor.username)), React.createElement(TutorRating, { tutor: this.props.tutor, language: this.props.language, style: { display: "inline", marginLeft: 10, textAlign: "center" } })), !user.groupStudent && React.createElement("label", null, React.createElement("input", { type: "checkbox", onChange: this.toggleNotifyTutorOnline, checked: this.state.notify, ref: "notify" }), React.createElement("span", null, " Notify me when this tutor is online")), user.paid && !user.groupStudent && React.createElement("label", null, React.createElement("input", { type: "checkbox", onChange: this.toggleHideTutor, checked: hiddenTutors.ids.has(tutor.userId), disabled: this.state.hidingInProgress }), React.createElement("span", null, " Hide this tutor"))), React.createElement("div", { className: "col-xs-2 col-sm-1" }, React.createElement("button", { type: "button", className: "close", style: { padding: '16px' }, 'data-dismiss': "modal", 'aria-label': "Close" }, React.createElement("span", { 'aria-hidden': "true" }, "×"))))), React.createElement(TutorProfileSection, null, this.state.tutorVideoUrl && React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-8 col-xs-offset-2" }, React.createElement(TutorProfileVideo, { autoplay: this.props.autoplay, videoUrl: this.state.tutorVideoUrl }))), React.createElement("div", { className: "row text-center", style: { paddingTop: '8px', paddingBottom: '8px' } }, practiceButton, messageButton)), React.createElement(TutorProfileSection, { title: "Profile" }, React.createElement(TutorAttributesSection, { localizedAttributes: this.state.localizedAttributes })), React.Children.map(this.props.children, function (profileSection, i) { return profileSection && React.createElement(TutorProfileSection, { key: i, title: profileSection.props.title, tutor: tutor }, React.cloneElement(profileSection, { onUpdate: _this2.onSectionUpdate })); })))), this.props.reserveSessionModal); } })); var getTutorRating = function getTutorRating(tutor) { var language = arguments.length <= 1 || arguments[1] === undefined ? 'en' : arguments[1]; function getRating(tutorRating) { var language = arguments.length <= 1 || arguments[1] === undefined ? 'en' : arguments[1]; if (!tutorRating || !tutorRating[language]) { // error handling return null; } if ((tutorRating[language].numReviews || 0) < 50) { // not enough reviews to display yet return null; } else { return computeDisplayRating(tutorRating[language].rating); } } function computeDisplayRating(rating) { return Math.round(rating * 100) / 100; } return getRating(tutor.tutorRating, language); }; var TutorRating = (function (_React$Component) { _inherits(TutorRating, _React$Component); function TutorRating() { _classCallCheck(this, TutorRating); _get(Object.getPrototypeOf(TutorRating.prototype), 'constructor', this).apply(this, arguments); } _createClass(TutorRating, [{ key: 'render', value: function render() { var _props2 = this.props; var tutor = _props2.tutor; var language = _props2.language; var style = _props2.style; var rating = getTutorRating(tutor, language); if (!rating) { return React.createElement("div", { style: Object.assign({ color: "#00B300" }, style) }, React.createElement("h4", null, "New talent")); } return React.createElement("div", { style: Object.assign({ color: "#333333" }, style) }, React.createElement("h4", { style: { display: "block", marginTop: "0px", marginBottom: "0px" } }, React.createElement("img", { src: "/static/images/ic_star.svg", className: "rating-star", style: { height: "18px" } }), React.createElement("span", { style: { marginLeft: "5px" } }, rating), React.createElement("span", { style: { fontSize: "11px" } }, " / 5.0")), React.createElement("h6", { style: { display: "block", marginTop: "0px", marginBottom: "0px" } }, React.createElement("span", null, "Rating"))); } }]); return TutorRating; })(React.Component); var TutorProfileVideo = React.createClass({ displayName: 'TutorProfileVideo', componentDidMount: function componentDidMount() { if (this.props.autoplay) { var isPlaying = this.video.currentTime > 0 && !this.video.paused && !this.video.ended && this.video.readyState > 2; if (!isPlaying) { this.video.play(); } } }, render: function render() { var _this3 = this; return React.createElement("video", { ref: function ref(v) { return _this3.video = v; }, width: "100%", src: this.props.videoUrl, controls: true }, React.createElement("source", { type: "video/mp4" })); } }); var TutorProfileSection = React.createClass({ displayName: 'TutorProfileSection', render: function render() { var sectionHeadingStyle = { height: '100%', display: 'flex', flexFlow: 'column', backgroundColor: '#eee', alignItems: 'center' }; var sectionStyle = { paddingTop: '16px', paddingBottom: '16px' }; return React.createElement("div", null, this.props.title && React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-12" }, React.createElement("div", { style: sectionHeadingStyle }, React.createElement("h3", { className: "single-line" }, this.props.title)))), React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-12" }, React.createElement("div", { className: "bg-white", style: sectionStyle }, this.props.children)))); } }); var TutorAttributesSection = React.createClass({ displayName: 'TutorAttributesSection', render: function render() { if (!this.props.localizedAttributes.length) { return null; } return React.createElement("table", { className: "table table-sm", style: { 'tableLayout': 'fixed' } }, React.createElement("tbody", null, this.props.localizedAttributes.map(function (attribute, i) { return React.createElement("tr", { key: i }, React.createElement("td", { colSpan: "1", style: { width: '30%', fontWeight: 'bold' } }, React.createElement("h5", null, attribute.attr)), React.createElement("td", { colSpan: "2", style: { display: 'flex', flexFlow: 'row wrap' } }, attribute.vals.map(function (val) { return React.createElement("span", { key: val, className: "label label-primary", style: { fontWeight: 'normal', fontSize: '100%', margin: '3px' } }, val); }))); }))); } }); var TutorAboutMeSection = React.createClass({ displayName: 'TutorAboutMeSection', aboutMeSections: function aboutMeSections() { return [{ 'key': 'profession', 'title': "Profession" }, { 'key': 'experience', 'title': "Teaching Experience" }, { 'key': 'education', 'title': "Education" }, { 'key': 'interests', 'title': "Interests" }]; }, render: function render() { var _this4 = this; return React.createElement("div", null, this.aboutMeSections().filter(function (element) { return element.key in _this4.props.tutor; }).map(function (element) { return React.createElement("div", { key: element.key }, React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-10 col-xs-offset-1" }, React.createElement("h5", { style: { 'fontWeight': 'bold' } }, element.title))), React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-9 col-xs-offset-2" }, React.createElement("p", null, _this4.props.tutor[element.key].replace(/\n$/g, '').split(/\n/).map(function (line, index) { return React.createElement("span", { key: index }, line, React.createElement("br", null)); }))))); })); } }); var TutorLibrarySection = React.createClass({ displayName: 'TutorLibrarySection', getInitialState: function getInitialState() { return { content: [] }; }, componentDidMount: function componentDidMount() { var _this5 = this; CAMBLY.get('/model/contents', { 'library': this.props.tutor.userId }).done(function (resp) { var topics = resp.result; var topics_i_submitetd = topics.filter(function (element) { return element.creator === _this5.props.tutor.userId; }); var other_topics = topics.filter(function (element) { return element.creator !== _this5.props.tutor.userId; }); _this5.setState({ content: topics_i_submitetd.concat(other_topics).slice(0, 10) }); }); }, componentDidUpdate: function componentDidUpdate() { if (this.props.onUpdate) { this.props.onUpdate(); } }, render: function render() { var _this6 = this; if (!this.state.content.length) { return React.createElement("div", null, React.createElement("em", null, "This tutor has not added any lessons")); } return React.createElement("table", { className: "table table-sm" }, React.createElement("tbody", null, this.state.content.map(function (content) { return React.createElement("tr", { key: content.id }, React.createElement("td", null, React.createElement("a", { href: content.url, target: "_blank" }, content.title)), React.createElement("td", null, _this6.props.tutorStatus == 'available' && React.createElement(PracticeButton, { className: "single-line btn-sm", language: _this6.props.language, user: _this6.props.user, tutor: _this6.props.tutor, title: "Discuss", contentRequest: content.id }))); }))); } }); var TutorUploadVideosSection = React.createClass({ displayName: 'TutorUploadVideosSection', getInitialState: function getInitialState() { return { uploadedVideos: null }; }, componentDidMount: function componentDidMount() { CAMBLY.get('/model/tutorVideo', { userId: this.props.tutor.userId }).done((function (data) { var uploadedVideos = data.result; this.setState({ uploadedVideos: uploadedVideos }); }).bind(this)); }, componentDidUpdate: function componentDidUpdate() { if (this.props.onUpdate) { this.props.onUpdate(); } }, render: function render() { var _this7 = this; if (!this.state.uploadedVideos) { return null; } else if (!this.state.uploadedVideos.length) { return React.createElement("div", null, React.createElement("em", null, "This tutor has not added any teaching videos")); } var isTutor = this.props.tutor.userId == this.props.user.userId; return React.createElement("div", { style: { display: 'flex', flexFlow: 'row wrap' } }, this.state.uploadedVideos.map(function (video) { return React.createElement(TutorVideoThumbnail, { key: video.id, video: video, isTutor: isTutor, tutorName: _this7.props.tutor.username, style: { width: 240, marginRight: 5 } }); })); } }); var TutorVideoThumbnail = (function (_React$Component2) { _inherits(TutorVideoThumbnail, _React$Component2); function TutorVideoThumbnail(props) { _classCallCheck(this, TutorVideoThumbnail); _get(Object.getPrototypeOf(TutorVideoThumbnail.prototype), 'constructor', this).call(this, props); this.state = {}; } _createClass(TutorVideoThumbnail, [{ key: 'render', value: function render() { var _props3 = this.props; var style = _props3.style; var video = _props3.video; var isTutor = _props3.isTutor; var shareData = { 'videoId': video.id, 'tutorName': this.props.tutorName }; var tweetUrl = 'https://twitter.com/intent/tweet?url=' + video.shortLink + '&via=cambly'; var popoverTop = React.createElement(ReactBootstrap.Popover, { id: "popover-contained", title: "Share this video" }, React.createElement("div", null, React.createElement(FBshareButton, { shareData: shareData, postType: "tutorVideo", style: { 'margin': '5px 0' } }), React.createElement("div", { style: { 'margin': '5px 0' } }, React.createElement("a", { href: tweetUrl, target: "_blank" }, React.createElement("button", { className: "btn btn-social btn-twitter", onClick: function onClick() { return CAMBLY.logUIEvent("share_attempt", { "socialMedia": "twitter" }); } }, React.createElement("i", { className: "fa fa-twitter" }), "Share on Twitter"))))); return React.createElement("div", { className: "thumbnail", style: Object.assign({ display: 'flex', flexFlow: 'column' }, style) }, React.createElement(TutorUploadVideoPlayer, { videoId: video.id, videoUrl: video.url, dontCountViews: isTutor }), React.createElement("div", { className: "caption", style: { display: 'flex', flexFlow: 'column' } }, React.createElement("h4", null, video.title), React.createElement("em", null, video.description), React.createElement("span", { style: { alignSelf: 'flex-end' } }, video.viewCount || 0, " Views")), React.createElement("div", { className: "footer", style: { marginTop: 'auto', borderTop: '1px #eee' } }, React.createElement("div", { className: "button-toolbar", style: { display: 'flex', flexFlow: 'column', alignItems: 'flex-start' } }, React.createElement(ReactBootstrap.OverlayTrigger, { trigger: "click", placement: "top", overlay: popoverTop }, React.createElement("button", { className: "btn btn-xs btn-info", onClick: function onClick() { return CAMBLY.logUIEvent("share", null); } }, "Share This Lesson With Your Friends!"))))); } }]); return TutorVideoThumbnail; })(React.Component); var TutorScheduleSection = React.createClass({ displayName: 'TutorScheduleSection', getInitialState: function getInitialState() { return { schedule: [], hasLibrary: false, reserveSession: null }; }, componentDidMount: function componentDidMount() { CAMBLY.getTutorSchedule(this.props.tutor.userId, this.props.reservationLength, this.props.proType || null).done((function (data) { this.setState({ schedule: data.schedule, hasLibrary: data.hasLibrary }); }).bind(this)); }, componentDidUpdate: function componentDidUpdate() { if (this.props.onUpdate) { this.props.onUpdate(); } }, openReservationModal: function openReservationModal(session) { // TODO(martha): probably shouldn't put react elements in the redux store store.dispatch(showModal('reserveSession', { modal: React.createElement(ScheduleSessionModal, { user: this.props.user, tutor: this.props.tutor, startTime: session.startTime.$date, endTime: session.endTime.$date, hasLibrary: this.state.hasLibrary, onHide: function onHide() { store.dispatch(hideModal('reserveSession')); } }) })); }, render: function render() { var _this8 = this; var _props4 = this.props; var tutor = _props4.tutor; var user = _props4.user; if (!this.state.schedule.length) { if (tutor.userId == user.userId) { return React.createElement("div", { className: "alert alert-warning" }, "Students are able to book lessons with you from this page; however, we are unable to show you a preview since how we display your availability depends on the student's plan type." + ' ' + "You can check on your schedule ", React.createElement("a", { href: "/en/tutor/reservations" }, "here"), "."); } return React.createElement("div", null, React.createElement("em", null, "This tutor has not opened any spots for reservations")); } return React.createElement("div", null, user.minutes < 15 && !user.planMinutesPerDay && React.createElement("div", { className: "row" }, React.createElement("div", { className: "col-xs-10 col-xs-offset-1" }, React.createElement("div", { className: "alert alert-warning" }, React.createElement("strong", null, "You must have at least 15 minutes available to schedule a session.")))), this.state.schedule.map(function (session) { var disabled = !session.reservable || user.minutes < 15 && !user.planMinutesPerDay; var start = moment.tz(session.startTime.$date, user.timezone); var end = moment.tz(session.endTime.$date, user.timezone); var startFormat = start.format('dddd l LT'); var endFormat = start.date() === end.date() ? end.format('LT') : end.format('ddd LT'); return React.createElement("div", { key: session.startTime.$date, className: "row", style: { paddingBottom: '16px' } }, React.createElement("div", { className: "col-xs-7 col-xs-offset-1" }, React.createElement("h4", { className: "single-line" }, startFormat + ' - ' + endFormat)), React.createElement("div", { className: "col-xs-3 " + (cambly.RTL ? "text-left" : "text-right") }, React.createElement("button", { className: "single-line btn btn-sm btn-accent", disabled: disabled, onClick: function onClick() { return _this8.openReservationModal(session); } }, session.reservable ? "Schedule" : "Booked"))); })); } });