PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / assets / src / apps / js / frontend / single-course.js

single-course.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.8, at assets/src/apps/js/frontend/single-course.js

447 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import SingleCourse from './single-course/index';
2 import lpModalOverlayCompleteItem from './show-lp-overlay-complete-item';
3 import lpModalOverlay from '../utils/lp-modal-overlay';
4 import courseCurriculumSkeleton from './single-curriculum/skeleton';
5 import lpMaterialsLoad from './material';
6 import TabsDragScroll from './tabs-scroll';
7 import { lpSetLoadingEl } from '../../../js/utils.js';
8 import Toastify from 'toastify-js';
9 import 'toastify-js/src/toastify.css';
10 import LPCopyToClipboard from '../../../js/frontend/copy-to-clipboard.js';
11
12 export default SingleCourse;
13
14 export const init = () => {
15 wp.element.render(
16 <SingleCourse />,
17 );
18 };
19
20 const $ = jQuery;
21
22 const initCourseTabs = function() {
23 $( '#learn-press-course-tabs' ).on(
24 'change',
25 'input[name="learn-press-course-tab-radio"]',
26 function( e ) {
27 const selectedTab = $( 'input[name="learn-press-course-tab-radio"]:checked' ).val();
28
29 LP.Cookies.set( 'course-tab', selectedTab );
30
31 $( 'label[for="' + $( e.target ).attr( 'id' ) + '"]' ).closest( 'li' ).addClass( 'active' ).siblings().removeClass( 'active' );
32 }
33 );
34 };
35
36 const initCourseSidebar = function initCourseSidebar() {
37 const $sidebar = $( '.course-summary-sidebar' );
38
39 if ( ! $sidebar.length ) {
40 return;
41 }
42
43 const $window = $( window );
44 const $scrollable = $sidebar.children();
45 const offset = $sidebar.offset();
46 let scrollTop = 0;
47 const maxHeight = $sidebar.height();
48 const scrollHeight = $scrollable.height();
49 const options = {
50 offsetTop: 32,
51 };
52
53 const onScroll = function() {
54 scrollTop = $window.scrollTop();
55
56 const top = scrollTop - offset.top + options.offsetTop;
57
58 if ( top < 0 ) {
59 $sidebar.removeClass( 'slide-top slide-down' );
60 $scrollable.css( 'top', '' );
61 return;
62 }
63
64 if ( top > maxHeight - scrollHeight ) {
65 $sidebar.removeClass( 'slide-down' ).addClass( 'slide-top' );
66 $scrollable.css( 'top', maxHeight - scrollHeight );
67 } else {
68 $sidebar.removeClass( 'slide-top' ).addClass( 'slide-down' );
69 $scrollable.css( 'top', options.offsetTop );
70 }
71 };
72
73 $window.on( 'scroll.fixed-course-sidebar', onScroll ).trigger( 'scroll.fixed-course-sidebar' );
74 };
75
76 // Rest API Enroll course - Nhamdv.
77 const enrollCourse = () => {
78 const formEnrolls = document.querySelectorAll( 'form.enroll-course' );
79
80 if ( formEnrolls.length > 0 ) {
81 formEnrolls.forEach( ( formEnroll ) => {
82 const submit = async ( id, btnEnroll ) => {
83 const status = 'error';
84
85 try {
86 const response = await wp.apiFetch( {
87 path: 'lp/v1/courses/enroll-course',
88 method: 'POST',
89 data: { id },
90 } );
91
92 const { status, data: { redirect }, message } = response;
93
94 if ( status === 'success' ) {
95 btnEnroll.remove();
96 } else {
97 lpSetLoadingEl( btnEnroll, 0 );
98 throw new Error( message );
99 }
100
101 if ( message && status ) {
102 formEnroll.innerHTML += `<div class="learn-press-message ${ status }">${ message }</div>`;
103 if ( redirect ) {
104 window.location.href = redirect;
105 }
106 }
107 } catch ( error ) {
108 Toastify( {
109 text: error.message,
110 gravity: lpData.toast.gravity, // `top` or `bottom`
111 position: lpData.toast.position, // `left`, `center` or `right`
112 className: `${ lpData.toast.classPrefix } ${ status }`,
113 close: lpData.toast.close == 1,
114 stopOnFocus: lpData.toast.stopOnFocus == 1,
115 duration: lpData.toast.duration,
116 } ).showToast();
117 }
118 };
119
120 formEnroll.addEventListener( 'submit', ( event ) => {
121 event.preventDefault();
122 const id = formEnroll.querySelector( 'input[name=enroll-course]' ).value;
123 const btnEnroll = formEnroll.querySelector( 'button.button-enroll-course' );
124 lpSetLoadingEl( btnEnroll, 1 );
125 submit( id, btnEnroll );
126 } );
127 } );
128 }
129
130 // Reload when press back button in chrome.
131 if ( document.querySelector( '.course-detail-info' ) !== null ) {
132 window.addEventListener( 'pageshow', ( event ) => {
133 const hasCache = event.persisted || ( typeof window.performance != 'undefined' && String( window.performance.getEntriesByType( 'navigation' )[ 0 ].type ) == 'back_forward' );
134 if ( hasCache ) {
135 location.reload();
136 }
137 } );
138 }
139 };
140
141 // Rest API purchase course - Nhamdv.
142 const purchaseCourse = () => {
143 const forms = document.querySelectorAll( 'form.purchase-course' );
144
145 if ( forms.length > 0 ) {
146 forms.forEach( ( form ) => {
147 // Allow Repurchase.
148 const allowRepurchase = () => {
149 const continueRepurchases = document.querySelectorAll( '.lp_allow_repurchase_select' );
150
151 continueRepurchases.forEach( ( repurchase ) => {
152 const radios = repurchase.querySelectorAll( '[name=_lp_allow_repurchase_type]' );
153
154 for ( let i = 0, length = radios.length; i < length; i++ ) {
155 if ( radios[ i ].checked ) {
156 const repurchaseType = radios[ i ].value;
157 const id = form.querySelector( 'input[name=purchase-course]' ).value;
158
159 const btnBuyNow = form.querySelector( 'button.button-purchase-course' );
160 lpSetLoadingEl( btnBuyNow, 1 );
161
162 submit( id, btnBuyNow, repurchaseType );
163 break;
164 }
165 }
166 } );
167 };
168
169 const submit = async ( id, btn, repurchaseType = false ) => {
170 const status = 'error';
171
172 try {
173 const formData = new FormData( form );
174 const dataSend = Object.fromEntries( Array.from( formData.keys(), ( key ) => {
175 const val = formData.getAll( key );
176
177 return [ key, val.length > 1 ? val : val.pop() ];
178 } ) );
179
180 dataSend.id = id;
181 dataSend.repurchaseType = repurchaseType;
182
183 const response = await wp.apiFetch( {
184 path: 'lp/v1/courses/purchase-course',
185 method: 'POST',
186 data: dataSend,
187 } );
188
189 const { status, data: { redirect, type, html, titlePopup }, message } = response;
190
191 if ( status === 'success' ) {
192 if ( type === 'allow_repurchase' ) {
193 lpSetLoadingEl( btn, 0 );
194 } else {
195 btn.remove();
196 }
197 } else {
198 lpSetLoadingEl( btn, 0 );
199 throw new Error( message );
200 }
201
202 if ( type === 'allow_repurchase' && status === 'success' ) {
203 if ( ! form.querySelector( '.lp_allow_repurchase_select' ) ) {
204 if ( ! lpModalOverlay.init() ) {
205 return;
206 }
207
208 lpModalOverlay.elLPOverlay.show();
209
210 lpModalOverlay.setTitleModal( titlePopup || '' );
211
212 lpModalOverlay.setContentModal( html );
213
214 lpModalOverlay.callBackYes = () => {
215 lpModalOverlay.elLPOverlay.hide();
216
217 allowRepurchase();
218 };
219 }
220 } else if ( message && status ) {
221 form.innerHTML += `<div class="learn-press-message ${ status }">${ message }</div>`;
222
223 if ( 'success' === status && redirect ) {
224 window.location.href = redirect;
225 }
226 }
227 } catch ( error ) {
228 Toastify( {
229 text: error.message,
230 gravity: lpData.toast.gravity, // `top` or `bottom`
231 position: lpData.toast.position, // `left`, `center` or `right`
232 className: `${ lpData.toast.classPrefix } ${ status }`,
233 close: lpData.toast.close == 1,
234 stopOnFocus: lpData.toast.stopOnFocus == 1,
235 duration: lpData.toast.duration,
236 } ).showToast();
237 }
238 };
239
240 form.addEventListener( 'submit', ( event ) => {
241 event.preventDefault();
242 const id = form.querySelector( 'input[name=purchase-course]' ).value;
243 const btn = form.querySelector( 'button.button-purchase-course' );
244 lpSetLoadingEl( btn, 1 );
245 submit( id, btn );
246 } );
247 } );
248 }
249 };
250
251 const retakeCourse = () => {
252 const elFormRetakeCourses = document.querySelectorAll( '.lp-form-retake-course' );
253
254 if ( ! elFormRetakeCourses.length ) {
255 return;
256 }
257
258 elFormRetakeCourses.forEach( ( elFormRetakeCourse ) => {
259 const elButtonRetakeCourses = elFormRetakeCourse.querySelector( '.button-retake-course' );
260 const elCourseId = elFormRetakeCourse.querySelector( '[name=retake-course]' ).value;
261 const elAjaxMessage = elFormRetakeCourse.querySelector( '.lp-ajax-message' );
262 const submit = ( elButtonRetakeCourse ) => {
263 wp.apiFetch( {
264 path: '/lp/v1/courses/retake-course',
265 method: 'POST',
266 data: { id: elCourseId },
267 } ).then( ( res ) => {
268 const { status, message, data } = res;
269 elAjaxMessage.innerHTML = message;
270
271 if ( undefined != status && status === 'success' ) {
272 elButtonRetakeCourse.style.display = 'none';
273 setTimeout( () => {
274 window.location.replace( data.url_redirect );
275 }, 1000 );
276 } else {
277 elAjaxMessage.classList.add( 'error' );
278 }
279 } ).catch( ( err ) => {
280 elAjaxMessage.classList.add( 'error' );
281 elAjaxMessage.innerHTML = 'error: ' + err.message;
282 } ).then( () => {
283 elButtonRetakeCourse.classList.remove( 'loading' );
284 elButtonRetakeCourse.disabled = false;
285 elAjaxMessage.style.display = 'block';
286 } );
287 };
288
289 elFormRetakeCourse.addEventListener( 'submit', ( e ) => {
290 e.preventDefault();
291 } );
292
293 elButtonRetakeCourses.addEventListener(
294 'click',
295 ( e ) => {
296 e.preventDefault();
297 elButtonRetakeCourses.classList.add( 'loading' );
298 elButtonRetakeCourses.disabled = true;
299 submit( elButtonRetakeCourses );
300 }
301 );
302 } );
303 };
304
305 // Rest API load content course progress - Nhamdv.
306 const courseProgress = () => {
307 const elements = document.querySelectorAll( '.lp-course-progress-wrapper' );
308
309 if ( ! elements.length ) {
310 return;
311 }
312
313 if ( 'IntersectionObserver' in window ) {
314 const eleObserver = new IntersectionObserver( ( entries, observer ) => {
315 entries.forEach( ( entry ) => {
316 if ( entry.isIntersecting ) {
317 const ele = entry.target;
318
319 setTimeout( function() {
320 getResponse( ele );
321 }, 600 );
322
323 eleObserver.unobserve( ele );
324 }
325 } );
326 } );
327
328 [ ...elements ].map( ( ele ) => eleObserver.observe( ele ) );
329 }
330
331 const getResponse = async ( ele ) => {
332 let url = 'lp/v1/lazy-load/course-progress';
333 if ( lpData.urlParams.hasOwnProperty( 'lang' ) ) {
334 url += '?lang=' + lpData.urlParams.lang;
335 }
336
337 const response = await wp.apiFetch( {
338 path: url,
339 method: 'POST',
340 data: {
341 courseId: lpGlobalSettings.post_id || '',
342 userId: lpData.user_id || '',
343 },
344 } );
345
346 const { data } = response;
347
348 ele.innerHTML = data;
349 };
350 };
351
352 const accordionExtraTab = () => {
353 const elements = document.querySelectorAll( '.course-extra-box' );
354 [ ...elements ].map( ( ele ) => {
355 const title = ele.querySelector( '.course-extra-box__title' );
356 ele.classList.remove( 'active' );
357 const content = ele.querySelector( '.course-extra-box__content' );
358 content.style.height = '0';
359
360 title.addEventListener( 'click', () => {
361 const isActive = ele.classList.contains( 'active' );
362
363 [ ...elements ].forEach( ( otherEle ) => {
364 if ( otherEle !== ele ) {
365 otherEle.classList.remove( 'active' );
366 otherEle.querySelector( '.course-extra-box__content' ).style.height = '0';
367 }
368 } );
369
370 if ( isActive ) {
371 ele.classList.remove( 'active' );
372 content.style.height = '0';
373 } else {
374 ele.classList.add( 'active' );
375 content.style.height = content.scrollHeight + 'px';
376 }
377 } );
378 } );
379 };
380
381 const courseContinue = () => {
382 const formContinue = document.querySelectorAll( 'form.continue-course' );
383 if ( formContinue.length && lpData.user_id > 0 ) {
384 const getResponse = async ( ele ) => {
385 const response = await wp.apiFetch( {
386 path: 'lp/v1/courses/continue-course',
387 method: 'POST',
388 data: {
389 courseId: lpGlobalSettings.post_id || '',
390 userId: lpGlobalSettings.user_id || '',
391 },
392 } );
393
394 return response;
395 };
396
397 getResponse( formContinue ).then( function( result ) {
398 if ( result.status === 'success' ) {
399 formContinue.forEach( ( form ) => {
400 form.style.display = 'inline-block';
401 form.action = result.data;
402 } );
403 }
404 } );
405 }
406 };
407
408 export {
409 initCourseTabs,
410 initCourseSidebar,
411 enrollCourse,
412 };
413
414 document.addEventListener( 'DOMContentLoaded', function() {
415 const $popup = $( '#popup-course' );
416 let timerClearScroll;
417 const $curriculum = $( '#learn-press-course-curriculum' );
418 accordionExtraTab();
419 initCourseTabs();
420 initCourseSidebar();
421 enrollCourse();
422 purchaseCourse();
423 retakeCourse();
424 courseProgress();
425 courseContinue();
426 lpModalOverlayCompleteItem.init();
427 lpMaterialsLoad();
428 //courseCurriculumSkeleton();
429 TabsDragScroll();
430 LPCopyToClipboard();
431 } );
432
433 const detectedElCurriculum = setInterval( function() {
434 const elementCurriculum = document.querySelector( '.learnpress-course-curriculum' );
435 if ( elementCurriculum ) {
436 courseCurriculumSkeleton();
437
438 clearInterval( detectedElCurriculum );
439 }
440 }, 1 );
441
442 // Add callback for Thimkits
443 LP.Hook.addAction( 'lp_course_curriculum_skeleton', function( id ) {
444 courseCurriculumSkeleton( id );
445 } );
446
447