PluginProbe
Elementor Website Builder – more than just a page builder / 3.8.0-beta1
Elementor Website Builder – more than just a page builder v3.8.0-beta1
4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 All 457 releases
elementor / app / modules / kit-library / assets / js / pages / index / index.js

index.js in Elementor Website Builder – more than just a page builder 3.8.0-beta1, at app/modules/kit-library/assets/js/pages/index/index.js

308 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import Content from '../../../../../../assets/js/layout/content';
2 import EnvatoPromotion from '../../components/envato-promotion';
3 import ErrorScreen from '../../components/error-screen';
4 import FilterIndicationText from '../../components/filter-indication-text';
5 import IndexHeader from './index-header';
6 import IndexSidebar from './index-sidebar';
7 import KitList from '../../components/kit-list';
8 import Layout from '../../components/layout';
9 import PageLoader from '../../components/page-loader';
10 import SearchInput from '../../components/search-input';
11 import SortSelect from '../../components/sort-select';
12 import TaxonomiesFilter from '../../components/taxonomies-filter';
13 import useKits, { defaultQueryParams } from '../../hooks/use-kits';
14 import usePageTitle from 'elementor-app/hooks/use-page-title';
15 import useTaxonomies from '../../hooks/use-taxonomies';
16 import { Grid } from '@elementor/app-ui';
17 import { useCallback, useMemo, useEffect } from 'react';
18 import { useLastFilterContext } from '../../context/last-filter-context';
19 import { useLocation } from '@reach/router';
20 import { appsEventTrackingDispatch } from 'elementor-app/event-track/apps-event-tracking';
21
22 import './index.scss';
23
24 /**
25 * Generate select and unselect taxonomy functions.
26 *
27 * @param {Function} setQueryParams
28 * @return {((function(*, *): *)|(function(*=): *))[]} taxonomy functions
29 */
30 function useTaxonomiesSelection( setQueryParams ) {
31 const selectTaxonomy = useCallback( ( type, callback ) => setQueryParams(
32 ( prev ) => {
33 const taxonomies = { ...prev.taxonomies };
34
35 taxonomies[ type ] = callback( prev.taxonomies[ type ] );
36
37 return { ...prev, taxonomies };
38 },
39 ), [ setQueryParams ] );
40
41 const unselectTaxonomy = useCallback( ( taxonomy ) => setQueryParams( ( prev ) => {
42 const taxonomies = Object.entries( prev.taxonomies )
43 .reduce( ( current, [ key, groupedTaxonomies ] ) => ( {
44 ...current,
45 [ key ]: groupedTaxonomies.filter( ( item ) => item !== taxonomy ),
46 } ), {} );
47
48 return { ...prev, taxonomies };
49 } ), [ setQueryParams ] );
50
51 return [ selectTaxonomy, unselectTaxonomy ];
52 }
53
54 /**
55 * Generate the menu items for the index page.
56 *
57 * @param {string} path
58 * @return {Array} menu items
59 */
60 function useMenuItems( path ) {
61 return useMemo( () => {
62 const page = path.replace( '/', '' );
63
64 return [
65 {
66 label: __( 'All Website Kits', 'elementor' ),
67 icon: 'eicon-filter',
68 isActive: ! page,
69 url: '/kit-library',
70 trackEventData: { command: 'kit-library/select-organizing-category', category: 'all' },
71 },
72 {
73 label: __( 'Favorites', 'elementor' ),
74 icon: 'eicon-heart-o',
75 isActive: 'favorites' === page,
76 url: '/kit-library/favorites',
77 trackEventData: { command: 'kit-library/select-organizing-category', category: 'favorites' },
78 },
79 ];
80 }, [ path ] );
81 }
82
83 /**
84 * Update and read the query param from the url
85 *
86 * @param {*} queryParams
87 * @param {*} setQueryParams
88 * @param {Array<string>} exclude
89 */
90 function useRouterQueryParams( queryParams, setQueryParams, exclude = [] ) {
91 const location = useLocation(),
92 { setLastFilter } = useLastFilterContext();
93
94 useEffect( () => {
95 const filteredQueryParams = Object.fromEntries(
96 Object.entries( queryParams )
97 .filter( ( [ key, item ] ) => ! exclude.includes( key ) && item ),
98 );
99
100 setLastFilter( filteredQueryParams );
101
102 history.replaceState(
103 null,
104 '',
105 decodeURI(
106 `#${ wp.url.addQueryArgs( location.pathname.split( '?' )[ 0 ] || '/', filteredQueryParams ) }`,
107 ),
108 );
109 }, [ queryParams ] );
110
111 useEffect( () => {
112 const routerQueryParams = Object.keys( defaultQueryParams ).reduce( ( current, key ) => {
113 // TODO: Replace with `wp.url.getQueryArgs` when WordPress 5.7 is the min version
114 const queryArg = wp.url.getQueryArg( location.pathname, key );
115
116 if ( ! queryArg ) {
117 return current;
118 }
119
120 return {
121 ...current,
122 [ key ]: queryArg,
123 };
124 }, {} );
125
126 setQueryParams( ( prev ) => ( {
127 ...prev,
128 ...routerQueryParams,
129 taxonomies: {
130 ...prev.taxonomies,
131 ...routerQueryParams.taxonomies,
132 },
133 ready: true,
134 } ) );
135 }, [] );
136 }
137
138 export default function Index( props ) {
139 usePageTitle( {
140 title: __( 'Kit Library', 'elementor' ),
141 } );
142
143 const menuItems = useMenuItems( props.path );
144
145 const {
146 data,
147 isSuccess,
148 isLoading,
149 isFetching,
150 isError,
151 queryParams,
152 setQueryParams,
153 clearQueryParams,
154 forceRefetch,
155 isFilterActive,
156 } = useKits( props.initialQueryParams );
157
158 useRouterQueryParams( queryParams, setQueryParams, [ 'ready', ...Object.keys( props.initialQueryParams ) ] );
159
160 const {
161 data: taxonomiesData,
162 forceRefetch: forceRefetchTaxonomies,
163 isFetching: isFetchingTaxonomies,
164 } = useTaxonomies();
165
166 const [ selectTaxonomy, unselectTaxonomy ] = useTaxonomiesSelection( setQueryParams );
167
168 const eventTracking = ( command, elementPosition, search = null, direction = null, sortType = null, action = null, eventType = 'click' ) => {
169 appsEventTrackingDispatch(
170 command,
171 {
172 page_source: 'home page',
173 element_position: elementPosition,
174 search_term: search,
175 sort_direction: direction,
176 sort_type: sortType,
177 event_type: eventType,
178 action,
179 },
180 );
181 };
182
183 return (
184 <Layout
185 sidebar={
186 <IndexSidebar
187 tagsFilterSlot={ <TaxonomiesFilter
188 selected={ queryParams.taxonomies }
189 onSelect={ selectTaxonomy }
190 taxonomies={ taxonomiesData }
191 category={ props.path }
192 /> }
193 menuItems={ menuItems }
194 />
195 }
196 header={
197 <IndexHeader
198 refetch={ () => {
199 forceRefetch();
200 forceRefetchTaxonomies();
201 } }
202 isFetching={ isFetching || isFetchingTaxonomies }
203 />
204 }
205 >
206 <div className="e-kit-library__index-layout-container">
207 <Grid container className="e-kit-library__index-layout-top-area">
208 <Grid item className="e-kit-library__index-layout-top-area-search">
209 <SearchInput
210 // eslint-disable-next-line @wordpress/i18n-ellipsis
211 placeholder={ __( 'Search all Website Kits...', 'elementor' ) }
212 value={ queryParams.search }
213 onChange={ ( value ) => {
214 setQueryParams( ( prev ) => ( { ...prev, search: value } ) );
215 eventTracking( 'kit-library/kit-free-search', 'top_area_search', value, null, null, null, 'search' );
216 } }
217 />
218 { isFilterActive && <FilterIndicationText
219 queryParams={ queryParams }
220 resultCount={ data.length || 0 }
221 onClear={ clearQueryParams }
222 onRemoveTag={ unselectTaxonomy }
223 /> }
224 </Grid>
225 <Grid
226 item
227 className="e-kit-library__index-layout-top-area-sort"
228 >
229 <SortSelect
230 options={ [
231 {
232 label: __( 'Featured', 'elementor' ),
233 value: 'featuredIndex',
234 defaultOrder: 'asc',
235 orderDisabled: true,
236 },
237 {
238 label: __( 'New', 'elementor' ),
239 value: 'createdAt',
240 defaultOrder: 'desc',
241 },
242 {
243 label: __( 'Popular', 'elementor' ),
244 value: 'popularityIndex',
245 defaultOrder: 'desc',
246 },
247 {
248 label: __( 'Trending', 'elementor' ),
249 value: 'trendIndex',
250 defaultOrder: 'desc',
251 },
252 ] }
253 value={ queryParams.order }
254 onChange={ ( order ) => setQueryParams( ( prev ) => ( { ...prev, order } ) ) }
255 onChangeSortDirection={ ( direction ) => eventTracking( 'kit-library/change-sort-direction', 'top_area_sort', null, direction ) }
256 onChangeSortValue={ ( value ) => eventTracking( 'kit-library/change-sort-value', 'top_area_sort', null, null, value ) }
257 onSortSelectOpen={ () => eventTracking( 'kit-library/change-sort-type', 'top_area_sort', null, null, null, 'expand' ) }
258 />
259 </Grid>
260 </Grid>
261 <Content className="e-kit-library__index-layout-main">
262 <>
263 { isLoading && <PageLoader /> }
264 {
265 isError && <ErrorScreen
266 title={ __( 'Something went wrong.', 'elementor' ) }
267 description={ __( 'Nothing to worry about, use 🔄 on the top right to try again. If the problem continues, head over to the Help Center.', 'elementor' ) }
268 button={ {
269 text: __( 'Learn More', 'elementor' ),
270 url: 'http://go.elementor.com/app-kit-library-error/',
271 target: '_blank',
272 } }
273 />
274 }
275 { isSuccess && 0 < data.length && queryParams.ready && <KitList data={ data } queryParams={ queryParams } source={ props.path } /> }
276 {
277 isSuccess && 0 === data.length && queryParams.ready && props.renderNoResultsComponent( {
278 defaultComponent: <ErrorScreen
279 title={ __( 'No results matched your search.', 'elementor' ) }
280 description={ __( 'Try different keywords or ', 'elementor' ) }
281 button={ {
282 text: __( 'Continue browsing.', 'elementor' ),
283 action: clearQueryParams,
284 category: props.path,
285 } }
286 />,
287 isFilterActive,
288 } )
289 }
290 <EnvatoPromotion category={ props.path } />
291 </>
292 </Content>
293 </div>
294 </Layout>
295 );
296 }
297
298 Index.propTypes = {
299 path: PropTypes.string,
300 initialQueryParams: PropTypes.object,
301 renderNoResultsComponent: PropTypes.func,
302 };
303
304 Index.defaultProps = {
305 initialQueryParams: {},
306 renderNoResultsComponent: ( { defaultComponent } ) => defaultComponent,
307 };
308