import { useCallback, useEffect, useState } from 'react'; import apiFetch from '@wordpress/api-fetch'; import type { AiAction } from '../lib/ai-runs'; import type { SeoEditorAi } from '../env'; /** What the AI buttons of the panel share: the right to press them, what ran, what is left. */ export interface AiGate { /** The user holds "AI with credits". */ allowed: boolean; /** What the page is, as the questions name it: "post", "product". */ kind: string; /** The actions that already spent credits on this page today. */ ranToday: readonly string[]; /** Credits left, once the site has asked Recomaze. */ balance: number | null; /** An action went through: it counts as run today, and the balance is asked again. */ onRan: (action: AiAction) => void; } /** * The AI gate of the page being edited. The balance is asked from the site * (the editors hold no Recomaze token) only when the user may spend it. * * @param ai - What the server said at load. * @param kind - What the page is: its type's label. * @param enabled - Whether the page offers any AI action at all. * @return The gate. */ export const useAiGate = ( ai: SeoEditorAi | undefined, kind: string, enabled: boolean ): AiGate => { const allowed = ai?.allowed ?? false; const [ranToday, setRanToday] = useState(ai?.ranToday ?? []); const [balance, setBalance] = useState(null); const [asked, setAsked] = useState(0); useEffect(() => { if (!allowed || !enabled) return undefined; let current = true; apiFetch<{ balance: number | null }>({ path: '/recomaze/v1/seo/credits' }) .then(answer => { if (current) setBalance(answer.balance ?? null); }) .catch(() => { if (current) setBalance(null); }); return () => { current = false; }; }, [allowed, enabled, asked]); const onRan = useCallback((action: AiAction): void => { setRanToday(ran => (ran.includes(action) ? ran : [...ran, action])); setAsked(count => count + 1); }, []); return { allowed, kind: kind.toLowerCase(), ranToday, balance, onRan }; };