'use client'; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet'; import { cn } from '@/lib/utils'; import { useMitt } from '@/plugins/MittContext'; import useMediaStore from '@/stores/MediaStore'; import useUserStore from '@/stores/UserStore'; import { usePage } from '@inertiajs/react'; import { useEffect, useRef, useState } from 'react'; import { toast } from 'sonner'; const EditorAISheet = () => { const [isOpen, setIsOpen] = useState(false); const [prompt, setPrompt] = useState(''); const emitter = useMitt(); const { generateMeme, isGeneratingMeme, keywords, isLoadingAIHints, fetchAIHints, checkMemeJobStatus, updateMemeResult, setGeneratingMeme, checkActiveJob, } = useMediaStore(); const pollingIntervalRef = useRef(null); const currentJobIdRef = useRef(null); const { credits } = useUserStore(); const { auth } = usePage().props; useEffect(() => { const openSheetListener = () => { setIsOpen(true); fetchAIHints(); }; emitter.on('open-ai-editor-sheet', openSheetListener); return () => { emitter.off('open-ai-editor-sheet', openSheetListener); }; }, [emitter, fetchAIHints]); // Check for active job on component mount useEffect(() => { if (auth.user) { checkForActiveJob(); } }, [auth.user]); const checkForActiveJob = async () => { try { const response = await checkActiveJob(); if (response?.success?.data) { const { job_id, status, result } = response.success.data; if (status === 'pending' || status === 'processing') { // Resume polling for active job setGeneratingMeme(true); currentJobIdRef.current = job_id; startPolling(job_id); } else if (status === 'completed' && result) { // Show completed result updateMemeResult(result); toast.success('Your previous meme generation completed!'); } } } catch (error) { // No active job or error - continue normally console.log('No active job found or error checking:', error); } }; const handleOpenChange = (open) => { setIsOpen(open); // If sheet is being closed while generating, stop polling if (!open && isGeneratingMeme) { stopPolling(); } }; const startPolling = (jobId) => { currentJobIdRef.current = jobId; // Clear existing interval if any if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current); } const checkJobStatus = async () => { try { const response = await checkMemeJobStatus(jobId); if (response?.success?.data) { const { status, result, error } = response.success.data; if (status === 'completed') { // Job completed successfully if (result?.generate) { updateMemeResult(result); stopPolling(); toast.success('Meme generated successfully!'); } } else if (status === 'failed') { // Job failed stopPolling(); setGeneratingMeme(false); toast.error(error || 'Failed to generate meme'); } // If status is 'pending' or 'processing', continue polling } } catch (error) { console.error('Error checking job status:', error); stopPolling(); setGeneratingMeme(false); toast.error('Error checking meme generation status'); } }; // Start polling every 5 seconds pollingIntervalRef.current = setInterval(checkJobStatus, 5000); // Also check immediately checkJobStatus(); }; const stopPolling = () => { if (pollingIntervalRef.current) { clearInterval(pollingIntervalRef.current); pollingIntervalRef.current = null; } currentJobIdRef.current = null; }; const handleSend = async () => { if (prompt.trim()) { try { const response = await generateMeme(prompt); if (response?.success?.data?.job_id) { startPolling(response.success.data.job_id); } } catch (error) { // Error already handled in store } } }; // Close sheet when generation is complete useEffect(() => { if (!isGeneratingMeme && isOpen && currentJobIdRef.current) { // Small delay to let user see the success message const timer = setTimeout(() => { setIsOpen(false); setPrompt(''); }, 1000); return () => clearTimeout(timer); } }, [isGeneratingMeme, isOpen]); // Cleanup polling on unmount useEffect(() => { return () => { stopPolling(); }; }, []); return ( button]:hidden')} onInteractOutside={(e) => isGeneratingMeme && e.preventDefault()} onEscapeKeyDown={(e) => isGeneratingMeme && e.preventDefault()} > AI features coming soon! {/* {isGeneratingMeme ? 'Creating...' : 'What meme would you like to create?'}
setPrompt(e.target.value)} className="bg-muted/30 max-h-20 min-h-12 resize-none rounded-3xl border-0 p-4 text-center text-base" /> {isLoadingAIHints &&
Loading AI hints...
} {keywords.length > 0 && !isLoadingAIHints && (
{keywords.map((keyword, index) => ( ))}
)}
{auth.user ? ( <>
A new meme costs 1 credit for AI captions & 1 credit for AI background.{' '}
You have {credits} credits remaining.
) : ( <>
/ to use AI features.
)}
*/}
); }; export default EditorAISheet;