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 / blocks / courses / course-item-template / edit.js

edit.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.8, at assets/src/apps/js/blocks/courses/course-item-template/edit.js

285 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 InnerBlocks,
3 useBlockProps,
4 BlockContextProvider,
5 useInnerBlocksProps,
6 InspectorControls,
7 // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
8 __experimentalUseBlockPreview as useBlockPreview,
9 store as blockEditorStore,
10 } from '@wordpress/block-editor';
11 import classnames from 'classnames';
12 import { useSelect } from '@wordpress/data';
13 import { memo, useMemo, useState, useEffect } from '@wordpress/element';
14 import {
15 PanelBody,
16 __experimentalToggleGroupControl as ToggleGroupControl,
17 __experimentalToggleGroupControlOption as ToggleGroupControlOption,
18 RangeControl,
19 } from '@wordpress/components';
20 import { __ } from '@wordpress/i18n';
21 import * as lpUtils from 'lpAssetsJsPath/utils.js';
22 import API from 'lpAssetsJsPath/api.js';
23 const TEMPLATE_DEFAULT = [
24 [ 'learnpress/course-image' ],
25 [ 'learnpress/course-title' ],
26 [ 'learnpress/course-price' ],
27 ];
28
29 function PostTemplateInnerBlocks( { classList } ) {
30 const innerBlocksProps = useInnerBlocksProps(
31 { className: classnames( 'wp-block-learnpress-course-item-template' ) },
32 { template: TEMPLATE_DEFAULT }
33 );
34 return (
35 <li className="course">
36 <div { ...innerBlocksProps }></div>
37 </li>
38 );
39 }
40
41 function PostTemplateBlockPreview( {
42 blocks,
43 blockContextId,
44 classList,
45 isHidden,
46 setActiveBlockContextId,
47 } ) {
48 const blockPreviewProps = useBlockPreview( {
49 blocks,
50 } );
51
52 const handleOnClick = () => {
53 setActiveBlockContextId( blockContextId );
54 };
55
56 const style = {
57 display: isHidden ? 'none' : undefined,
58 };
59
60 return (
61 <li
62 className="course"
63 tabIndex={ 0 }
64 // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
65 role="button"
66 onClick={ handleOnClick }
67 onKeyPress={ handleOnClick }
68 style={ style }
69 >
70 <div { ...blockPreviewProps } className="wp-block-learnpress-course-item-template"></div>
71 </li>
72 );
73 }
74
75 const fetchLearnPressCourses = async ( courseQuery, signal ) => {
76 let url = API.apiEditCoursesArchiveBlock;
77 url = lpUtils.lpAddQueryArgs( url, courseQuery );
78
79 const response = await fetch( url, {
80 method: 'GET',
81 signal,
82 } );
83
84 if ( ! response.ok ) {
85 throw new Error( `HTTP error! Status: ${ response.status }` );
86 }
87
88 return await response.json();
89 };
90
91 const MemoizedPostTemplateBlockPreview = memo( PostTemplateBlockPreview );
92
93 const Edit = ( { clientId, context, attributes, setAttributes } ) => {
94 const blockProps = useBlockProps( {
95 className: classnames( 'learn-press-courses' ),
96 } );
97 const [ activeBlockContextId, setActiveBlockContextId ] = useState();
98 const [ coursesData, setCoursesData ] = useState();
99 const [ listCourses, setListCourses ] = useState( [] );
100 const [ loadingAPI, setLoadingAPI ] = useState( 0 );
101 // const [ totalPages, setTotalPages ] = useState( 1 );
102 const { columns } = attributes;
103
104 const layoutPagination = context.lpCourseQuery?.pagination_type || 'number';
105
106 // Fetch courses when query parameters change
107 useEffect( () => {
108 const courseQuery = context.lpCourseQuery ?? {};
109 let signal, controller;
110 const fetchCourses = async () => {
111 try {
112 setLoadingAPI( 1 );
113 controller = new AbortController();
114 signal = controller.signal;
115
116 const response = await fetchLearnPressCourses( courseQuery, signal );
117 const { data } = response;
118 const { courses, page, total, total_pages } = data;
119
120 setCoursesData( response );
121 setListCourses( courses );
122 // setTotalPages( total_pages );
123 } catch ( error ) {
124 if ( error.name !== 'AbortError' ) {
125 console.error( 'Failed to fetch courses:', error );
126 }
127 } finally {
128 setLoadingAPI( 0 );
129 }
130 };
131
132 fetchCourses();
133
134 return () => {
135 controller.abort();
136 };
137 }, [ context.lpCourseQuery?.order_by, context.lpCourseQuery?.limit ] );
138
139 const { blocks } = useSelect(
140 ( select ) => {
141 const { getBlocks } = select( blockEditorStore );
142
143 return {
144 blocks: getBlocks( clientId ),
145 };
146 },
147 [ clientId ]
148 );
149
150 const blockContexts = useMemo(
151 () =>
152 listCourses?.map( ( course ) => ( {
153 lpCourseData: course,
154 courseId: course?.ID,
155 } ) ),
156 [ listCourses ]
157 );
158
159 if ( loadingAPI ) {
160 return (
161 <ul { ...blockProps }>
162 <li>{ __( 'Courses Fetching…', 'learnpress' ) }</li>
163 </ul>
164 );
165 }
166
167 if ( listCourses.length === 0 && ! loadingAPI ) {
168 const dataDummy = [
169 {
170 ID: 1,
171 post_title: __( 'Course One', 'learnpress' ),
172 },
173 {
174 ID: 2,
175 post_title: __( 'Course two', 'learnpress' ),
176 },
177 ];
178 setListCourses( dataDummy );
179 }
180
181 function paginationTypeDisplay( type ) {
182 switch ( type ) {
183 case 'load-more':
184 return (
185 <button className="courses-btn-load-more">{ __( 'Load More', 'learnpress' ) }</button>
186 );
187 case 'infinite':
188 return '';
189 default:
190 return (
191 <nav className="learnpress-block-pagination navigation pagination">
192 <ul className="page-numbers">
193 <li>
194 <a className="prev page-numbers" href="?paged=1">
195 <i className="lp-icon-arrow-left"></i>
196 </a>
197 </li>
198 { Array.from( { length: 3 }, ( _, index ) => (
199 <li key={ index }>
200 <a className="page-numbers" href="{index}">
201 { index + 1 }
202 </a>
203 </li>
204 ) ) }
205 </ul>
206 </nav>
207 );
208 }
209 }
210
211 return (
212 <>
213 <InspectorControls>
214 <PanelBody title={ __( 'Settings', 'learnpress' ) }>
215 <ToggleGroupControl
216 label={ __( 'Layout', 'learnpress' ) }
217 value={ attributes.layout || 'gird' }
218 onChange={ ( value ) => {
219 setAttributes( {
220 layout: value || 'gird',
221 } );
222 } }
223 isBlock={ true }
224 >
225 <ToggleGroupControlOption value="list" label="Stack" />
226 <ToggleGroupControlOption value="grid" label="Grid" />
227 </ToggleGroupControl>
228
229 { attributes.layout === 'grid' && (
230 <RangeControl
231 label={ __( 'Columns', 'learnpress' ) }
232 value={ attributes.columns || 3 }
233 onChange={ ( value ) => {
234 setAttributes( {
235 columns: value,
236 } );
237 } }
238 min={ 2 }
239 max={ 6 }
240 step={ 1 }
241 marks={ [
242 { value: 2, label: '2' },
243 { value: 3, label: '3' },
244 { value: 4, label: '4' },
245 { value: 5, label: '5' },
246 { value: 6, label: '6' },
247 ] }
248 withInputField={ true }
249 />
250 ) }
251 </PanelBody>
252 </InspectorControls>
253 <ul
254 className="learn-press-courses wp-block-learn-press-courses"
255 data-layout={ attributes.layout ? attributes.layout : 'list' }
256 style={ {
257 '--columns': attributes.columns || 3,
258 } }
259 >
260 { blockContexts &&
261 blockContexts.map( ( blockContext ) => (
262 <BlockContextProvider key={ blockContext.courseId } value={ blockContext }>
263 { blockContext.courseId ===
264 ( activeBlockContextId || blockContexts[ 0 ]?.courseId ) ? (
265 <PostTemplateInnerBlocks classList={ blockContext.classList } />
266 ) : null }
267 <MemoizedPostTemplateBlockPreview
268 blocks={ blocks }
269 blockContextId={ blockContext.courseId }
270 classList={ blockContext.classList }
271 setActiveBlockContextId={ setActiveBlockContextId }
272 isHidden={
273 blockContext.courseId === ( activeBlockContextId || blockContexts[ 0 ]?.courseId )
274 }
275 />
276 </BlockContextProvider>
277 ) ) }
278 </ul>
279 { context.lpCourseQuery?.pagination ? paginationTypeDisplay( layoutPagination ) : null }
280 </>
281 );
282 };
283
284 export default Edit;
285