File "index.js"

Full Path: /home/warrior1/public_html/languages/wp-content/plugins/elementor/app/modules/kit-library/assets/js/pages/index/index.js
File size: 9.1 KB
MIME-type: text/x-java
Charset: utf-8

import Content from '../../../../../../assets/js/layout/content';
import EnvatoPromotion from '../../components/envato-promotion';
import ErrorScreen from '../../components/error-screen';
import FilterIndicationText from '../../components/filter-indication-text';
import IndexHeader from './index-header';
import IndexSidebar from './index-sidebar';
import KitList from '../../components/kit-list';
import Layout from '../../components/layout';
import PageLoader from '../../components/page-loader';
import SearchInput from '../../components/search-input';
import SortSelect from '../../components/sort-select';
import TaxonomiesFilter from '../../components/taxonomies-filter';
import useKits, { defaultQueryParams } from '../../hooks/use-kits';
import usePageTitle from 'elementor-app/hooks/use-page-title';
import useTaxonomies from '../../hooks/use-taxonomies';
import { Grid } from '@elementor/app-ui';
import { useCallback, useMemo, useEffect } from 'react';
import { useLastFilterContext } from '../../context/last-filter-context';
import { useLocation } from '@reach/router';
import { appsEventTrackingDispatch } from 'elementor-app/event-track/apps-event-tracking';

import './index.scss';

/**
 * Generate select and unselect taxonomy functions.
 *
 * @param {Function} setQueryParams
 * @return {((function(*, *): *)|(function(*=): *))[]} taxonomy functions
 */
function useTaxonomiesSelection( setQueryParams ) {
	const selectTaxonomy = useCallback( ( type, callback ) => setQueryParams(
		( prev ) => {
			const taxonomies = { ...prev.taxonomies };

			taxonomies[ type ] = callback( prev.taxonomies[ type ] );

			return { ...prev, taxonomies };
		},
	), [ setQueryParams ] );

	const unselectTaxonomy = useCallback( ( taxonomy ) => setQueryParams( ( prev ) => {
		const taxonomies = Object.entries( prev.taxonomies )
			.reduce( ( current, [ key, groupedTaxonomies ] ) => ( {
				...current,
				[ key ]: groupedTaxonomies.filter( ( item ) => item !== taxonomy ),
			} ), {} );

		return { ...prev, taxonomies };
	} ), [ setQueryParams ] );

	return [ selectTaxonomy, unselectTaxonomy ];
}

/**
 * Generate the menu items for the index page.
 *
 * @param {string} path
 * @return {Array} menu items
 */
function useMenuItems( path ) {
	return useMemo( () => {
		const page = path.replace( '/', '' );

		return [
			{
				label: __( 'All Website Kits', 'elementor' ),
				icon: 'eicon-filter',
				isActive: ! page,
				url: '/kit-library',
				trackEventData: { command: 'kit-library/select-organizing-category', category: 'all' },
			},
			{
				label: __( 'Favorites', 'elementor' ),
				icon: 'eicon-heart-o',
				isActive: 'favorites' === page,
				url: '/kit-library/favorites',
				trackEventData: { command: 'kit-library/select-organizing-category', category: 'favorites' },
			},
		];
	}, [ path ] );
}

/**
 * Update and read the query param from the url
 *
 * @param {*}             queryParams
 * @param {*}             setQueryParams
 * @param {Array<string>} exclude
 */
function useRouterQueryParams( queryParams, setQueryParams, exclude = [] ) {
	const location = useLocation(),
		{ setLastFilter } = useLastFilterContext();

	useEffect( () => {
		const filteredQueryParams = Object.fromEntries(
			Object.entries( queryParams )
				.filter( ( [ key, item ] ) => ! exclude.includes( key ) && item ),
		);

		setLastFilter( filteredQueryParams );

		history.replaceState(
			null,
			'',
			decodeURI(
				`#${ wp.url.addQueryArgs( location.pathname.split( '?' )[ 0 ] || '/', filteredQueryParams ) }`,
			),
		);
	}, [ queryParams ] );

	useEffect( () => {
		const routerQueryParams = Object.keys( defaultQueryParams ).reduce( ( current, key ) => {
			// TODO: Replace with `wp.url.getQueryArgs` when WordPress 5.7 is the min version
			const queryArg = wp.url.getQueryArg( location.pathname, key );

			if ( ! queryArg ) {
				return current;
			}

			return {
				...current,
				[ key ]: queryArg,
			};
		}, {} );

		setQueryParams( ( prev ) => ( {
			...prev,
			...routerQueryParams,
			taxonomies: {
				...prev.taxonomies,
				...routerQueryParams.taxonomies,
			},
			ready: true,
		} ) );
	}, [] );
}

export default function Index( props ) {
	usePageTitle( {
		title: __( 'Kit Library', 'elementor' ),
	} );

	const menuItems = useMenuItems( props.path );

	const {
		data,
		isSuccess,
		isLoading,
		isFetching,
		isError,
		queryParams,
		setQueryParams,
		clearQueryParams,
		forceRefetch,
		isFilterActive,
	} = useKits( props.initialQueryParams );

	useRouterQueryParams( queryParams, setQueryParams, [ 'ready', ...Object.keys( props.initialQueryParams ) ] );

	const {
		data: taxonomiesData,
		forceRefetch: forceRefetchTaxonomies,
		isFetching: isFetchingTaxonomies,
	} = useTaxonomies();

	const [ selectTaxonomy, unselectTaxonomy ] = useTaxonomiesSelection( setQueryParams );

	const eventTracking = ( command, elementPosition, search = null, direction = null, sortType = null, action = null, eventType = 'click' ) => {
		appsEventTrackingDispatch(
			command,
			{
				page_source: 'home page',
				element_position: elementPosition,
				search_term: search,
				sort_direction: direction,
				sort_type: sortType,
				event_type: eventType,
				action,
			},
		);
	};

	return (
		<Layout
			sidebar={
				<IndexSidebar
					tagsFilterSlot={ <TaxonomiesFilter
						selected={ queryParams.taxonomies }
						onSelect={ selectTaxonomy }
						taxonomies={ taxonomiesData }
						category={ props.path }
					/> }
					menuItems={ menuItems }
				/>
			}
			header={
				<IndexHeader
					refetch={ () => {
						forceRefetch();
						forceRefetchTaxonomies();
					} }
					isFetching={ isFetching || isFetchingTaxonomies }
				/>
			}
		>
			<div className="e-kit-library__index-layout-container">
				<Grid container className="e-kit-library__index-layout-top-area">
					<Grid item className="e-kit-library__index-layout-top-area-search">
						<SearchInput
							// eslint-disable-next-line @wordpress/i18n-ellipsis
							placeholder={ __( 'Search all Website Kits...', 'elementor' ) }
							value={ queryParams.search }
							onChange={ ( value ) => {
								setQueryParams( ( prev ) => ( { ...prev, search: value } ) );
								eventTracking( 'kit-library/kit-free-search', 'top_area_search', value, null, null, null, 'search' );
							} }
						/>
						{ isFilterActive && <FilterIndicationText
							queryParams={ queryParams }
							resultCount={ data.length || 0 }
							onClear={ clearQueryParams }
							onRemoveTag={ unselectTaxonomy }
						/> }
					</Grid>
					<Grid
						item
						className="e-kit-library__index-layout-top-area-sort"
					>
						<SortSelect
							options={ [
								{
									label: __( 'Featured', 'elementor' ),
									value: 'featuredIndex',
									defaultOrder: 'asc',
									orderDisabled: true,
								},
								{
									label: __( 'New', 'elementor' ),
									value: 'createdAt',
									defaultOrder: 'desc',
								},
								{
									label: __( 'Popular', 'elementor' ),
									value: 'popularityIndex',
									defaultOrder: 'desc',
								},
								{
									label: __( 'Trending', 'elementor' ),
									value: 'trendIndex',
									defaultOrder: 'desc',
								},
							] }
							value={ queryParams.order }
							onChange={ ( order ) => setQueryParams( ( prev ) => ( { ...prev, order } ) ) }
							onChangeSortDirection={ ( direction ) => eventTracking( 'kit-library/change-sort-direction', 'top_area_sort', null, direction ) }
							onChangeSortValue={ ( value ) => eventTracking( 'kit-library/change-sort-value', 'top_area_sort', null, null, value ) }
							onSortSelectOpen={ () => eventTracking( 'kit-library/change-sort-type', 'top_area_sort', null, null, null, 'expand' ) }
						/>
					</Grid>
				</Grid>
				<Content className="e-kit-library__index-layout-main">
					<>
						{ isLoading && <PageLoader /> }
						{
							isError && <ErrorScreen
								title={ __( 'Something went wrong.', 'elementor' ) }
								description={ __( 'Nothing to worry about, use 🔄 on the top right to try again. If the problem continues, head over to the Help Center.', 'elementor' ) }
								button={ {
									text: __( 'Learn More', 'elementor' ),
									url: 'http://go.elementor.com/app-kit-library-error/',
									target: '_blank',
								} }
							/>
						}
						{ isSuccess && 0 < data.length && queryParams.ready && <KitList data={ data } queryParams={ queryParams } source={ props.path } /> }
						{
							isSuccess && 0 === data.length && queryParams.ready && props.renderNoResultsComponent( {
								defaultComponent: <ErrorScreen
									title={ __( 'No results matched your search.', 'elementor' ) }
									description={ __( 'Try different keywords or ', 'elementor' ) }
									button={ {
										text: __( 'Continue browsing.', 'elementor' ),
										action: clearQueryParams,
										category: props.path,
									} }
								/>,
								isFilterActive,
							} )
						}
						<EnvatoPromotion category={ props.path } />
					</>
				</Content>
			</div>
		</Layout>
	);
}

Index.propTypes = {
	path: PropTypes.string,
	initialQueryParams: PropTypes.object,
	renderNoResultsComponent: PropTypes.func,
};

Index.defaultProps = {
	initialQueryParams: {},
	renderNoResultsComponent: ( { defaultComponent } ) => defaultComponent,
};