# icon-element/trunk/admin/assets/js/admin-script.js

Icon Element – Icon Pack for Elementor Page Builder (6718 icons), version trunk. 502 lines.

- Page: https://pluginprobe.com/plugins/icon-element/trunk/code/admin/assets/js/admin-script.js
- Raw: https://pluginprobe.com/plugins/icon-element/trunk/raw/admin/assets/js/admin-script.js
- Modified: 2026-04-24T01:43:20+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/icon-element/trunk/code/admin/assets/js/admin-script.js#L10-L20`.

```javascript
/**
 * React Admin Panel - Admin Script
 */
(function(wp) {
    const { createElement: el, useState, useEffect, useRef } = wp.element;
    const { ToggleControl, TabPanel } = wp.components || {};
    const apiFetch = wp.apiFetch;

    const hasComponents = !!wp.components;
    const API_NAMESPACE = rapSettings.restNamespace;

    // ── Toast notifications ────────────────────────────────────────────────────

    const ToastContainer = ({ toasts }) => {
        if (!toasts.length) return null;
        return el('div', { className: 'rap-toast-container' },
            toasts.map(t =>
                el('div', { key: t.id, className: `rap-toast rap-toast-${t.type}` },
                    el('span', { className: 'rap-toast-icon' }, t.type === 'success' ? '✓' : '✕'),
                    el('span', {}, t.message)
                )
            )
        );
    };

    // ── Fallback tab bar ───────────────────────────────────────────────────────

    const FallbackTabs = ({ tabs, activeTab, onSelect }) =>
        el('div', { className: 'rap-nav-tabs' },
            tabs.map(tab =>
                el('button', {
                    key: tab.name,
                    className: `rap-nav-tab${activeTab === tab.name ? ' is-active' : ''}`,
                    onClick: () => onSelect(tab.name)
                }, tab.title)
            )
        );

    // ── Toggle item ────────────────────────────────────────────────────────────

const ToggleItem = ({ id, name, checked, onChange, previewUrl, locked }) => {
    const inner = hasComponents && ToggleControl
        ? el(ToggleControl, {
            label: name,
            checked,
            onChange: val => onChange(id, val),
            disabled: locked           // disable toggle when locked
        })
        : el('label', { className: 'rap-toggle-switch' },
            el('input', {
                type: 'checkbox',
                checked,
                onChange: e => onChange(id, e.target.checked),
                disabled: locked       // disable checkbox when locked
            }),
            el('span', { className: 'rap-toggle-track' },
                el('span', { className: 'rap-toggle-thumb' })
            ),
            el('span', { className: 'rap-toggle-label' }, name)
        );

    // 2. Add class "rap-toggle-locked" when locked
    return el('div', {
        className: `rap-toggle-item${checked ? ' is-enabled' : ''}${locked ? ' rap-toggle-locked' : ''}`
    },
        el('div', { className: 'rap-toggle-item-inner' }, inner),
        previewUrl && el('a', {
            href: previewUrl,
            target: '_blank',
            rel: 'noopener noreferrer',
            className: 'rap-preview-btn'
        }, 'Preview ↗')
    );
};

    // ── Plugin card helpers ────────────────────────────────────────────────────

    const decodeHtml = (str) => {
        if (!str) return str;
        const txt = document.createElement('textarea');
        txt.innerHTML = str;
        return txt.value;
    };

    const StarRating = ({ rating, numRatings }) => {
        if (!numRatings) return null;
        const filled = Math.round((rating || 0) / 20); // 0-100 → 0-5
        return el('div', { className: 'rap-star-rating' },
            [1, 2, 3, 4, 5].map(i =>
                el('span', { key: i, className: `rap-star${i <= filled ? ' rap-star-on' : ''}` }, '★')
            )
        );
    };

    const PluginCard = ({ plugin, onInstall, onActivate, isInstalling, buttonStates }) => {
        const [imgError, setImgError] = useState(false);
        const slug       = plugin.slug || '';
        const name       = decodeHtml(plugin.name || slug || 'Unknown Plugin');
        const desc       = decodeHtml(plugin.short_description || '');
        const version    = plugin.version || '';
        const author     = plugin.author || '';
        const rating     = plugin.rating || 0;
        const numRatings = plugin.num_ratings || 0;
        const pluginUrl  = plugin.plugin_url || `https://wordpress.org/plugins/${slug}/`;
        const state      = buttonStates[slug] || {};

        const requiresPlugins = plugin.requires_plugins || [];
        const requiresWoo = requiresPlugins.some(p => /woocommerce/i.test(p))
            || /woocommerce/i.test(name);

        let action;
        if (state.active) {
            action = el('span', { className: 'rap-badge rap-badge-active' },
                el('span', { className: 'rap-badge-dot' }),
                'Active'
            );
        } else if (state.installed) {
            action = el('button', {
                className: 'rap-btn rap-btn-outline',
                onClick: () => onActivate(slug),
                disabled: isInstalling
            }, isInstalling
                ? el('span', { className: 'rap-btn-inner' },
                    el('span', { className: 'rap-spinner-sm' }), 'Activating…'
                  )
                : 'Activate'
            );
        } else {
            action = el('button', {
                className: 'rap-btn rap-btn-primary',
                onClick: () => onInstall(slug),
                disabled: isInstalling
            }, isInstalling
                ? el('span', { className: 'rap-btn-inner' },
                    el('span', { className: 'rap-spinner-sm' }), 'Installing…'
                  )
                : 'Install'
            );
        }

        const iconEl = plugin.thumbnail && !imgError
            ? el('img', {
                src: plugin.thumbnail,
                alt: name,
                className: 'rap-plugin-icon',
                onError: () => setImgError(true)
            })
            : el('div', { className: 'rap-plugin-icon-fallback' }, name.charAt(0).toUpperCase());

        return el('div', { className: `rap-plugin-card${state.active ? ' is-active' : state.installed ? ' is-installed' : ''}` },
            el('div', { className: 'rap-plugin-card-top' },
                el('div', { className: 'rap-plugin-icon-wrap' }, iconEl),
                el('div', { className: 'rap-plugin-header' },
                    el('h3', { className: 'rap-plugin-name' }, name)
                )
            ),
            el('div', { className: 'rap-plugin-body' },
                desc && el('p', { className: 'rap-plugin-desc' }, desc),
                requiresWoo && el('span', { className: 'rap-woo-badge' },
                    el('span', { className: 'rap-woo-icon' }, 'W'),
                    'Requires WooCommerce'
                ),
                el('a', {
                    href: pluginUrl,
                    target: '_blank',
                    rel: 'noopener noreferrer',
                    className: 'rap-details-link'
                }, 'View Details ↗')
            ),
            el('div', { className: 'rap-plugin-card-footer' },
                el(StarRating, { rating, numRatings }),
                action
            )
        );
    };

    // ── Main App ───────────────────────────────────────────────────────────────

    const App = () => {
        const [settings,       setSettings]       = useState({});
        const [iconSets,       setIconSets]        = useState([]);
        const [activeTab,      setActiveTab]       = useState('general');
        const [isSaving,       setIsSaving]        = useState(false);
        const [isLoading,      setIsLoading]       = useState(true);
        const [loadError,      setLoadError]       = useState(null);
        const [toasts,         setToasts]          = useState([]);
        const [search,         setSearch]          = useState('');
        const [plugins,        setPlugins]         = useState([]);
        const [pluginsLoading, setPluginsLoading]  = useState(false);
        const [pluginsFailed,  setPluginsFailed]   = useState(false);
        const [pluginStatuses, setPluginStatuses]  = useState({});
        const [installingSlug, setInstallingSlug]  = useState(null);
        const toastId = useRef(0);
        const authors = rapSettings.authorSlugs || ['softtent'];
        const is_pro = rapSettings.ispro ;

        const addToast = (message, type = 'success') => {
            const id = ++toastId.current;
            setToasts(prev => [...prev, { id, message, type }]);
            setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 4000);
        };

        // Load settings on mount
        useEffect(() => {
            (async () => {
                try {
                    setIconSets(rapSettings.iconSets || []);
                    const data = await apiFetch({
                        path: `/${API_NAMESPACE}/settings`,
                        method: 'GET',
                        headers: { 'X-WP-Nonce': rapSettings.nonce }
                    });
                    setSettings(data);
                } catch (_) {
                    setLoadError('Could not load settings. Please reload the page.');
                } finally {
                    setIsLoading(false);
                }
            })();
        }, []);

        // Clear search and reset plugin error when switching tabs
        useEffect(() => {
            setSearch('');
            if (activeTab !== 'recommended-plugins') setPluginsFailed(false);
        }, [activeTab]);

        // Load plugins when recommended-plugins tab is first opened
        useEffect(() => {
            if (activeTab === 'recommended-plugins' && !plugins.length && !pluginsLoading) {
                fetchPlugins();
            }
        }, [activeTab]);

        const fetchPlugins = async () => {
            setPluginsLoading(true);
            setPluginsFailed(false);
            try {
                const data = await apiFetch({
                    path: `/${API_NAMESPACE}/plugins?authors=${encodeURIComponent(authors.join(','))}`,
                    method: 'GET',
                    headers: { 'X-WP-Nonce': rapSettings.nonce }
                });

                const raw = Array.isArray(data)       ? data
                    : data && data.plugins             ? data.plugins
                    : data && typeof data === 'object' ? Object.values(data).filter(p => p && typeof p === 'object')
                    : [];

                // Pin softtent-managex to the top of the list
                const list = [
                    ...raw.filter(p => p.slug === 'softtent-managex'),
                    ...raw.filter(p => p.slug !== 'softtent-managex')
                ];
                setPlugins(list);

                const statuses = {};
                await Promise.all(list.map(async p => {
                    if (!p.slug) return;
                    try {
                        statuses[p.slug] = await apiFetch({
                            path: `/${API_NAMESPACE}/plugin-status?slug=${encodeURIComponent(p.slug)}`,
                            method: 'GET',
                            headers: { 'X-WP-Nonce': rapSettings.nonce }
                        });
                    } catch (_) {
                        statuses[p.slug] = { installed: false, active: false };
                    }
                }));
                setPluginStatuses(statuses);
            } catch (_) {
                // Only mark failed on a real REST/network exception
                setPluginsFailed(true);
            } finally {
                setPluginsLoading(false);
            }
        };

        const handleInstall = async (slug) => {
            setInstallingSlug(slug);
            try {
                await apiFetch({
                    path: `/${API_NAMESPACE}/install-plugin`,
                    method: 'POST',
                    headers: { 'X-WP-Nonce': rapSettings.nonce, 'Content-Type': 'application/json' },
                    body: JSON.stringify({ slug })
                });
                const status = await apiFetch({
                    path: `/${API_NAMESPACE}/plugin-status?slug=${encodeURIComponent(slug)}`,
                    method: 'GET',
                    headers: { 'X-WP-Nonce': rapSettings.nonce }
                });
                setPluginStatuses(prev => ({ ...prev, [slug]: status }));
                addToast('Plugin installed successfully!');
            } catch (e) {
                addToast('Install failed: ' + (e.message || 'Unknown error'), 'error');
            } finally {
                setInstallingSlug(null);
            }
        };

        const handleActivate = async (slug) => {
            setInstallingSlug(slug);
            try {
                await apiFetch({
                    path: `/${API_NAMESPACE}/activate-plugin`,
                    method: 'POST',
                    headers: { 'X-WP-Nonce': rapSettings.nonce, 'Content-Type': 'application/json' },
                    body: JSON.stringify({ slug })
                });
                const status = await apiFetch({
                    path: `/${API_NAMESPACE}/plugin-status?slug=${encodeURIComponent(slug)}`,
                    method: 'GET',
                    headers: { 'X-WP-Nonce': rapSettings.nonce }
                });
                setPluginStatuses(prev => ({ ...prev, [slug]: status }));
                addToast('Plugin activated!');
            } catch (e) {
                addToast('Activation failed: ' + (e.message || 'Unknown error'), 'error');
            } finally {
                setInstallingSlug(null);
            }
        };

        const handleSave = async () => {
            setIsSaving(true);
            try {
                const response = await apiFetch({
                    path: `/${API_NAMESPACE}/settings`,
                    method: 'POST',
                    headers: { 'X-WP-Nonce': rapSettings.nonce, 'Content-Type': 'application/json' },
                    body: JSON.stringify(settings)
                });
                setSettings(response);
                addToast('Settings saved!');
            } catch (_) {
                addToast('Save failed. Please try again.', 'error');
            } finally {
                setIsSaving(false);
            }
        };

        const freeIcons = iconSets.filter(i => !i.pro);
        const proIcons  = iconSets.filter(i =>  i.pro);

const renderIconGrid = (icons) => {
    const enabledCount = icons.filter(i => settings[i.id]).length;
    const filtered = search
        ? icons.filter(i => i.name.toLowerCase().includes(search.toLowerCase()))
        : icons;

    return el('div', {},
        el('div', { className: 'rap-toolbar' },
            el('div', { className: 'rap-chips' },
                el('span', { className: 'rap-chip rap-chip-primary' }, `${enabledCount} enabled`),
                el('span', { className: 'rap-chip' }, `${icons.length} total`)
            ),
            el('input', {
                type: 'text',
                className: 'rap-search',
                placeholder: 'Search icon sets…',
                value: search,
                onChange: e => setSearch(e.target.value)
            })
        ),
        filtered.length === 0
            ? el('p', { className: 'rap-empty' }, `No results for "${search}"`)
            : el('div', { className: 'rap-icon-grid' },
                filtered.map(icon => {
                    const locked = icon.pro && !is_pro;   // compute locked flag
                    return el(ToggleItem, {
                        key: icon.id,
                        id: icon.id,
                        name: icon.name,
                        checked: !!settings[icon.id],
                        onChange: (id, val) => setSettings(prev => ({ ...prev, [id]: val })),
                        previewUrl: icon.preview,
                        locked                          // pass locked prop
                    });
                })
            )
    );
};

        const renderPluginsTab = () => {
            if (pluginsLoading) {
                return el('div', { className: 'rap-loading' },
                    el('span', { className: 'rap-spinner' }),
                    el('span', {}, 'Loading plugins…')
                );
            }
            if (pluginsFailed) {
                return el('div', { className: 'rap-empty rap-empty-center' },
                    el('span', { className: 'rap-empty-icon' }, '⚠️'),
                    el('p', {}, 'Plugins could not be loaded.'),
                    el('button', {
                        className: 'rap-btn rap-btn-primary',
                        onClick: fetchPlugins
                    }, 'Try Again')
                );
            }
            if (!plugins.length) {
                return el('div', { className: 'rap-empty rap-empty-center' },
                    el('span', { className: 'rap-empty-icon' }, '📦'),
                    el('p', {}, 'No plugins found.')
                );
            }
            const statVals     = Object.values(pluginStatuses);
            const activeCount  = statVals.filter(s => s.active).length;
            const readyCount   = statVals.filter(s => s.installed && !s.active).length;

            return el('div', {},
                el('div', { className: 'rap-toolbar' },
                    el('div', { className: 'rap-chips' },
                        el('span', { className: 'rap-chip rap-chip-success' }, `${activeCount} active`),
                        readyCount > 0 && el('span', { className: 'rap-chip rap-chip-warning' }, `${readyCount} installed`),
                        el('span', { className: 'rap-chip' }, `${plugins.length} total`)
                    )
                ),
                el('div', { className: 'rap-plugins-grid' },
                    plugins.map(p =>
                        el(PluginCard, {
                            key: p.slug,
                            plugin: p,
                            onInstall: handleInstall,
                            onActivate: handleActivate,
                            isInstalling: installingSlug === p.slug,
                            buttonStates: pluginStatuses
                        })
                    )
                )
            );
        };

        if (isLoading) {
            return el('div', { className: 'rap-loading' },
                el('span', { className: 'rap-spinner' }),
                el('span', {}, 'Loading…')
            );
        }
        if (loadError) {
            return el('div', { className: 'rap-notice rap-notice-error' }, loadError);
        }

        const tabs = [
            { name: 'general',              title: `Free Icons (${freeIcons.length} Sets)` },
            { name: 'advanced',             title: `Pro Icons (${proIcons.length} Sets)` },
            { name: 'recommended-plugins',  title: 'Recommended Plugins' }
        ];

        const getTabContent = name => {
            if (name === 'general')             return renderIconGrid(freeIcons);
            if (name === 'advanced')            return renderIconGrid(proIcons);
            if (name === 'recommended-plugins') return renderPluginsTab();
            return null;
        };

        const showSave = activeTab === 'general' || activeTab === 'advanced';

        return el('div', { className: 'rap-app' },
            el(ToastContainer, { toasts }),
            el('div', { className: 'rap-panel' },
                hasComponents && TabPanel
                    ? el(TabPanel, {
                        className: 'rap-tabs',
                        activeClass: 'is-active',
                        tabs,
                        onSelect: setActiveTab,
                        children: tab => el('div', { className: 'rap-tab-body' }, getTabContent(tab.name))
                    })
                    : el('div', {},
                        el(FallbackTabs, { tabs, activeTab, onSelect: setActiveTab }),
                        el('div', { className: 'rap-tab-body' }, getTabContent(activeTab))
                    ),
                showSave && el('div', { className: 'rap-footer' },
                    el('button', {
                        className: `rap-btn rap-btn-primary rap-btn-lg${isSaving ? ' is-loading' : ''}`,
                        onClick: handleSave,
                        disabled: isSaving
                    }, isSaving
                        ? el('span', { className: 'rap-btn-inner' },
                            el('span', { className: 'rap-spinner-sm' }),
                            'Saving…'
                          )
                        : 'Save Settings'
                    )
                )
            )
        );
    };

    // Mount
    const root = document.getElementById('rap-root');
    if (root) {
        if (wp.element.createRoot) {
            wp.element.createRoot(root).render(el(App));
        } else {
            wp.element.render(el(App), root);
        }
    }

})(window.wp);
```
