import { __ } from "@wordpress/i18n"; import { useCallback, useMemo, memo, useState } from "@wordpress/element"; import { decodeEntities } from "@wordpress/html-entities"; import { RadioControl, Tooltip } from "@wordpress/components"; import { HeartIcon, HeartIconFull, ImportIcon, PreviewIcon, ProBadgeIcon, RotateIcon } from "./icons"; import { DEFAULTS, KEYBOARD_KEYS, API_ENDPOINTS } from "./constants"; import { FilterPart, HeaderWithFilter } from "./filter/filterPart"; import { currentBlockTitle } from "./controls"; const RenderFilterLabel = ({ label, number }) => { return ( <> {label} {`(${number || 0})`} ); }; const getPatternCategories = (categoryCounts, allCount) => { return [ { label: , value: "all", }, ...Object.keys(categoryCounts).map((blockName) => ({ label: , value: blockName, })), ]; }; const Skeleton = (props) => { const { type, size, loop, unit, c_s, classes } = props; const getSize = () => { let css = {}; switch (type) { case "image": case "circle": css = { width: size ? size + "px" : "300px", height: size ? size + "px" : "300px", }; break; case "title": css = { width: `${size ? size : "100"}${unit ? unit : "%"}`, }; break; case "button": css = { width: size ? size + "px" : "90px" }; break; case "custom_size": css = { width: `${c_s.size1 ? c_s.size1 : "100"}${c_s.unit1 ? c_s.unit1 : "%"}`, height: `${c_s.size2 ? c_s.size2 : "20"}${c_s.unit2 ? c_s.unit2 : "px"}`, borderRadius: c_s.br ? c_s.br + "px" : "0px", }; break; default: break; } return css; }; return ( <> {loop ? ( <> {Array(parseInt(loop)) .fill("1") .map((x, i) => { return (
); })} ) : (
)} ); }; // Individual Card Component. const PremadeCard = memo(({ data, wishListArr, setWListAction, reload, reloadId, onImport }) => { const isInWishlist = wishListArr?.includes(String(data.ID)); const isLoading = reload && reloadId === data.ID; const isPro = data.pro; // const isPro = false; const handleWishlistClick = useCallback(() => { setWListAction(data.ID, isInWishlist ? "remove" : ""); }, [data.ID, isInWishlist, setWListAction]); const handleImportClick = useCallback(() => { if (!isPro) { onImport(data.ID, data.pro); } }, [data.ID, data.pro, isPro, onImport]); return (
{data.name}
{decodeEntities(data?.name || "")}
{ if (e.key === KEYBOARD_KEYS.ENTER || e.key === KEYBOARD_KEYS.SPACE) { handleWishlistClick(); } }} aria-label={ isInWishlist ? __("Remove from wishlist", "easy-accordion-free") : __("Add to wishlist", "easy-accordion-free") } > {isInWishlist ? : } {isPro ? ( {__("PRO", "easy-accordion-free")} ) : ( { if (e.key === KEYBOARD_KEYS.ENTER || e.key === KEYBOARD_KEYS.SPACE) { handleImportClick(); } }} aria-label={__("Import", "easy-accordion-free") + " " + data.name} style={ isLoading ? { pointerEvents: "none", opacity: 0.6, } : {} } > {isLoading ? ( ) : ( <> {__("Import", "easy-accordion-free")} )} )}
); }); // Loading Skeleton Component. const LoadingSkeleton = memo(() => (
{Array(25) .fill(null) .map((_, i) => (
))}
)); // Empty State Component. const EmptyState = memo(() => ( {__("No Data found...", "easy-accordion-free")} )); // Main Grid Component. const PremadeGrid = memo( ({ premadeLists, column, searchQuery, freePro, showWishList, wishListArr, // localizedData, setWListAction, reload, reloadId, onImport, loading, }) => { // Memoize filter function const filteredLists = useMemo(() => { return premadeLists.filter((data) => { const searchMatch = !searchQuery || data.name?.toLowerCase().includes(searchQuery.toLowerCase()); const freeProMatch = freePro === "all" || (freePro === "pro" && data.pro) || (freePro === "free" && !data.pro); const wishListMatch = !showWishList || wishListArr?.includes(String(data.ID)); return searchMatch && freeProMatch && wishListMatch; }); }, [premadeLists, searchQuery, freePro, showWishList, wishListArr]); // Loading state. if (loading) { return ; } // Empty state if (filteredLists.length === 0) { return ; } // Grid with data return (
{filteredLists.map((data) => ( ))}
); } ); // Main StarterSites Component const StarterSites = (props) => { const { filterValue, state, setState, // useState, // useEffect, // useRef, _changeVal, filterByCategoryKey, setWListAction, wishListArr, _fetchFile, onClose, currentBlockName, isSingleBlock, } = props; const { current, designs, reload, reloadId, categoryCounts, freeCount, proCount, fetching, loading } = state; // const localizedData = sp_eab_patterns_post_block_localize || {}; // Local state management. const [column, setColumn] = useState(DEFAULTS.COLUMN); const [searchQuery, setSearchQuery] = useState(DEFAULTS.SEARCH_QUERY); const [trend, setTrend] = useState(DEFAULTS.TREND); const [freePro, setFreePro] = useState(DEFAULTS.FREE_PRO); const [showWishList, setShowWishList] = useState(false); const totalCount = freeCount + proCount; // Memoize sorted lists. const premadeLists = useMemo(() => { if (!current.length) return []; const lists = [...current]; if (trend === "latest" || trend === "all") { return lists.sort((a, b) => b.ID - a.ID); } if (trend === "popular" && lists[0]?.hit !== undefined) { return lists.sort((a, b) => b.hit - a.hit); } return lists; }, [current, trend]); const allCategoryCount = premadeLists?.length; const patternCategories = getPatternCategories(categoryCounts, totalCount); // Handle filter changes. const handleFilterChange = useCallback( (type) => { const filteredData = type === "all" ? designs : filterByCategoryKey(designs, type); setState((prev) => ({ ...prev, designFilter: type, current: filteredData, })); }, [designs, filterByCategoryKey, setState] ); // Unified state change handler. const changeStates = useCallback( (type, value) => { const handlers = { freePro: () => setFreePro(value), search: () => setSearchQuery(value), column: () => setColumn(value), wishlist: () => setShowWishList(value), trend: () => setTrend(value), filter: () => handleFilterChange(value), }; handlers[type]?.(); }, [handleFilterChange] ); // Memoize import handler. const handleImport = useCallback( (templateID, isPro) => { _changeVal(templateID, isPro); }, [_changeVal] ); const freeProOptions = [ { value: "all", label: , }, { value: "free", label: , }, { value: "pro", label: , }, ]; return ( <> {isSingleBlock && ( )}
{!isSingleBlock && (
{ changeStates("freePro", v); }} /> { changeStates("filter", v); }} />
)}
{!isSingleBlock && ( )}
); }; export default StarterSites;