import { createRoot } from 'react-dom/client';
import { __ } from '@wordpress/i18n';
import { useState, Suspense, memo } from '@wordpress/element';
import {
Badge,
Skeleton,
Drawer,
Container,
Button,
Text,
} from '@bsf/force-ui';
import { BarChart, X } from 'lucide-react';
import { AnimatePresence, motion } from 'framer-motion';
import { SureRankFullLogo } from '@GlobalComponents/icons';
import PageChecks from '@SeoPopup/components/page-seo-checks/page-checks';
import { useDispatch, useSuspenseSelect } from '@wordpress/data';
import PageChecksListSkeleton from '@/apps/seo-popup/components/page-seo-checks/page-checks-list-skeleton';
import { STORE_NAME } from '@Store/constants';
import '@Store/store';
import './style.scss';
const SeoChecksDrawer = ( {
open,
setOpen,
seoChecks,
errorMessage,
pageTitle,
postId,
postType,
} ) => {
const { ignoreSeoBarCheck, restoreSeoBarCheck } = useDispatch( STORE_NAME );
const handleCloseClick = ( e ) => {
e.preventDefault();
e.stopPropagation();
setOpen( false );
};
const handleIgnoreClick = ( checkId ) => {
ignoreSeoBarCheck( checkId, postId, postType );
};
const handleRestoreClick = ( checkId ) => {
restoreSeoBarCheck( checkId, postId, postType );
};
return (
}
onClick={ handleCloseClick }
className="text-text-secondary hover:text-text-primary"
aria-label={ __( 'Close drawer', 'surerank' ) }
/>
{ pageTitle +
' - ' +
__( 'Page SEO Checks', 'surerank' ) }
{ ! seoChecks || errorMessage ? (
{ errorMessage ||
__(
'No SEO data available.',
'surerank'
) }
) : (
}>
) }
);
};
const CustomBadge = ( { id, spanElement, forceRefresh = null } ) => {
const [ drawerOpen, setDrawerOpen ] = useState( false );
const isTaxonomy = window?.surerank_seo_bar?.type === 'taxonomy';
const { checks: seoChecks, error: errorMessage } = useSuspenseSelect(
( select ) =>
select( STORE_NAME )?.getSeoBarChecks(
id,
isTaxonomy ? 'taxonomy' : 'post',
forceRefresh
),
[]
);
const title =
spanElement?.getAttribute( 'data-title' ) ||
__( 'Untitled', 'surerank' );
const handleBadgeClick = () => {
setDrawerOpen( true );
};
let badgeProps = {
icon: ,
variant: 'green',
label: __( 'Optimized', 'surerank' ),
className: 'w-fit',
};
if ( ! seoChecks || errorMessage ) {
badgeProps = {
...badgeProps,
variant: 'red',
label: errorMessage || __( 'No Data', 'surerank' ),
};
} else if ( seoChecks.badChecks.length > 0 ) {
badgeProps = {
...badgeProps,
variant: 'red',
label: __( 'Issues Detected', 'surerank' ),
};
} else if ( seoChecks.fairChecks.length > 0 ) {
badgeProps = {
...badgeProps,
variant: 'yellow',
label: __( 'Needs Improvement', 'surerank' ),
};
}
return (
<>
{
if ( e.key === 'Enter' || e.key === ' ' ) {
handleBadgeClick( e );
}
} }
>
}
>
>
);
};
const CustomBadgeMemoized = memo( CustomBadge );
// Store root instances to properly cleanup
const rootInstances = new Map();
const renderBadge = ( span, forceRefresh = false ) => {
const id = span.getAttribute( 'data-id' );
if ( ! id ) {
return;
}
// Skip if already rendered and not forcing refresh
if ( ! forceRefresh && span.dataset.rendered === 'true' ) {
return;
}
// Cleanup existing root if it exists
const existingRoot = rootInstances.get( span );
if ( existingRoot ) {
try {
existingRoot.unmount();
} catch ( e ) {}
rootInstances.delete( span );
}
// Create new root and render
try {
const root = createRoot( span );
rootInstances.set( span, root );
root.render(
);
span.dataset.rendered = 'true'; // Mark as rendered
} catch ( e ) {}
};
const renderBadges = () => {
const spans = document.querySelectorAll(
'span.surerank-page-score[data-id]'
);
spans.forEach( ( span ) => {
renderBadge( span, null );
} );
};
// Debounce function to prevent multiple rapid calls
const debounce = ( func, wait ) => {
let timeout;
return function executedFunction( ...args ) {
const later = () => {
clearTimeout( timeout );
func( ...args );
};
clearTimeout( timeout );
timeout = setTimeout( later, wait );
};
};
/* global MutationObserver, inlineEditTax, Node */
// Initialize badges on page load
document.addEventListener( 'DOMContentLoaded', () => {
if (
window.location.pathname.includes( 'edit.php' ) ||
window.location.pathname.includes( 'edit-tags.php' )
) {
renderBadges();
}
// Set up MutationObserver to watch for new span elements
const table = document.querySelector( '#the-list' );
if ( table ) {
const observer = new MutationObserver( ( mutations ) => {
mutations.forEach( ( mutation ) => {
if ( mutation.addedNodes.length ) {
mutation.addedNodes.forEach( ( node ) => {
if ( node.nodeType === Node.ELEMENT_NODE ) {
const spans = node.querySelectorAll(
'span.surerank-page-score[data-id]'
);
spans.forEach( ( span ) => {
if ( ! span.dataset.rendered ) {
renderBadge( span, Date.now() ); // Force refresh for new terms
}
} );
}
} );
}
} );
} );
observer.observe( table, {
childList: true,
subtree: true,
} );
}
} );
// Handle inline edit for existing terms
document.addEventListener( 'DOMContentLoaded', () => {
if (
typeof inlineEditTax !== 'undefined' &&
typeof inlineEditTax.save === 'function'
) {
const originalTaxSave = inlineEditTax.save;
inlineEditTax.save = function ( id ) {
let termId = id;
if ( id && typeof id === 'object' && id.nodeType ) {
try {
const row = id.closest( 'tr[id^="tag-"], tr[id^="edit-"]' );
const idStr = row ? row.id : null;
if ( idStr ) {
const parts = idStr.split( '-' );
termId = parts[ parts.length - 1 ];
} else {
return;
}
} catch ( e ) {
return;
}
} else if ( typeof id === 'string' && id.startsWith( 'tag-' ) ) {
termId = id.replace( 'tag-', '' );
}
const result = originalTaxSave.call( this, termId );
const debouncedRerender = debounce( () => {
const span = document.querySelector(
`span.surerank-page-score[data-id="${ termId }"]`
);
if ( span ) {
renderBadge( span, Date.now() );
}
}, 3000 );
debouncedRerender();
return result;
};
}
} );
export default memo( CustomBadge );