import { useRef, useState } from 'react'; import { GaugeIcon, LoaderCircleIcon } from 'lucide-react'; import { analyze } from '../../editor/analysis/analyzer'; import { fetchSeoScoreQueue, storeSeoScores, } from '../../service/seo/seo.service'; import { Button } from '../ui/button'; import { Checkbox } from '../ui/checkbox'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../ui/dialog'; import { Progress } from '../ui/progress'; interface Tally { scored: number; total: number; low: number; sum: number; } const EMPTY: Tally = { scored: 0, total: 0, low: 0, sum: 0 }; /** * Scores every page with the editor's own analysis, twenty at a time: * the site hands over what the analyzer reads of each page, the scores go * back and land in the post lists. The pages without a current score by * default, every page on request. It runs while the dialog is open and * can be stopped; what was scored stays. */ export const ScoreRunner = ({ open, onClose, onDone, }: { open: boolean; onClose: () => void; onDone?: () => void; }): JSX.Element => { const [all, setAll] = useState(false); const [running, setRunning] = useState(false); const [finished, setFinished] = useState(false); const [tally, setTally] = useState(EMPTY); const [error, setError] = useState(''); const stop = useRef(false); const run = async (): Promise => { stop.current = false; setRunning(true); setFinished(false); setError(''); let current = { ...EMPTY }; setTally(current); try { let after = 0; const siteHost = window.location.host; for (;;) { const queue = await fetchSeoScoreQueue(all, after); if (queue.counts) { current = { ...current, total: all ? queue.counts.total : queue.counts.needed, }; setTally(current); } if (queue.items.length === 0 || stop.current) { break; } const scores: Record = {}; for (const item of queue.items) { const { score } = analyze({ ...item.input, siteHost, scope: 'post', }); scores[item.id] = score; current = { ...current, low: current.low + (score < 51 ? 1 : 0), sum: current.sum + score, }; } await storeSeoScores(scores); current = { ...current, scored: current.scored + queue.items.length, }; setTally(current); after = queue.items[queue.items.length - 1].id; } setFinished(true); onDone?.(); } catch (reason) { setError((reason as Error).message); } finally { setRunning(false); } }; const percent = tally.total > 0 ? Math.round((tally.scored / tally.total) * 100) : 0; const average = tally.scored > 0 ? Math.round(tally.sum / tally.scored) : 0; return ( { if (!next && !running) { onClose(); } }} > Score every page The same analysis the editor runs when a page is opened, for every published page at once: title, description, keyword, content, links and images. It spends no credits and changes nothing but the score. Keep this window open while it runs.
{(running || finished) && (

{tally.total === 0 && finished ? 'Every page already has a current score.' : `${tally.scored.toLocaleString()} of ${tally.total.toLocaleString()} pages scored`} {tally.scored > 0 && ` · average ${average} · ${tally.low.toLocaleString()} below 51`}

)} {error &&

{error}

}
{running ? ( ) : ( )}
); };