import { useDeferredValue, useEffect, useMemo, useState } from 'react'; import apiFetch from '@wordpress/api-fetch'; import { keywordIdeas } from '../analysis/keyword-ideas'; interface SearchIdea { query: string; impressions: number; clicks: number; position: number | null; } const chipClass = 'inline-flex max-w-full items-center gap-1 truncate rounded-full border border-border bg-background px-2 py-0.5 text-xs text-foreground hover:bg-muted'; /** * Ideas for the focus keyword under the field: the phrases the page itself * keeps coming back to, and what people typed into Google around the * strongest of them, from the site's Search Console. One click adds one. * * @param props - Component props. * @param props.title - The page's title. * @param props.html - Its content. * @param props.existing - The keywords set already. * @param props.onPick - Adds an idea as a keyword. * @param props.searched - The user may read Search Console's queries. * @return The ideas, or nothing when there are none. */ export const KeywordIdeas = ({ title, html, existing, onPick, searched: withSearches = false, }: { title: string; html: string; existing: string[]; onPick: (keyword: string) => void; searched?: boolean; }): JSX.Element | null => { const text = useDeferredValue(html); const fromPage = useMemo( () => keywordIdeas({ title, html: text }, existing), [title, text, existing] ); const seed = fromPage[0] ?? title .toLowerCase() .split(/\s+/) .filter(word => word.length > 2) .slice(0, 3) .join(' '); const [fromGoogle, setFromGoogle] = useState([]); useEffect(() => { if (!withSearches || seed.trim() === '') { setFromGoogle([]); return undefined; } let stale = false; const timer = window.setTimeout(() => { apiFetch<{ ideas: SearchIdea[] }>({ path: `/recomaze/v1/seo/keyword-ideas?search=${encodeURIComponent(seed)}`, }) .then(answer => !stale && setFromGoogle(answer.ideas ?? [])) .catch(() => !stale && setFromGoogle([])); }, 1500); return () => { stale = true; window.clearTimeout(timer); }; }, [seed, withSearches]); const taken = existing.map(keyword => keyword.toLowerCase()); const searched = fromGoogle.filter( idea => !taken.includes(idea.query.toLowerCase()) ); if (fromPage.length === 0 && searched.length === 0) { return null; } return (
{fromPage.length > 0 && ( <> Ideas from this page
{fromPage.map(idea => ( ))}
)} {searched.length > 0 && ( <> What people searched for, from Search Console (90 days)
{searched.map(idea => ( ))}
)}
); };