import React, { useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; import { X, Heart, Star } from 'lucide-react'; import { saveReviewAnswer, sendReviewFeedback } from '../../api'; const REVIEW_URL = 'https://wordpress.org/support/plugin/image-sizes/reviews/#new-post'; type Step = 'ask' | 'happy' | 'unhappy' | 'thanks'; interface Props { /** Pre-filled reply address; the admin can change it. */ email: string; onClose: () => void; } /** * Asks once, in a corner card, a while after install, whether ThumbPress is working out. Happy goes to WordPress.org; * unhappy can tell us privately, or still leave a public review. Closing it (X, Escape) counts as * "Maybe later": the server snoozes it, and a second "later" ends it for good. */ export default function ReviewPrompt( { email, onClose }: Props ) { const card = useRef( null ); const [ step, setStep ] = useState< Step >( 'ask' ); const [ message, setMessage ] = useState( '' ); const [ reply, setReply ] = useState( email ); const [ sending, setSending ] = useState( false ); const [ error, setError ] = useState( '' ); const later = () => { // "thanks" means the server already has the outcome; closing must not snooze over it. if ( step !== 'thanks' ) { saveReviewAnswer( 'later' ).catch( () => {} ); } onClose(); }; useEffect( () => { card.current?.focus(); const onKey = ( e: KeyboardEvent ) => { if ( 'Escape' === e.key ) { later(); } }; document.addEventListener( 'keydown', onKey ); return () => document.removeEventListener( 'keydown', onKey ); }, [ step ] ); const leaveReview = () => { saveReviewAnswer( 'reviewed' ).catch( () => {} ); window.open( REVIEW_URL, '_blank', 'noopener,noreferrer' ); setStep( 'thanks' ); }; const never = () => { saveReviewAnswer( 'never' ).catch( () => {} ); onClose(); }; const send = async () => { setSending( true ); setError( '' ); try { await sendReviewFeedback( message, reply ); setStep( 'thanks' ); } catch ( e: any ) { setError( e?.message || __( 'Feedback could not be sent right now. Please try again.', 'image-sizes' ) ); } finally { setSending( false ); } }; const primary = 'cursor-pointer rounded-lg border-0 bg-thumbpress-primary px-5 py-3 text-sm font-medium text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50'; const secondary = 'cursor-pointer rounded-lg border border-solid border-[#E2E8F0] bg-white px-5 py-3 text-sm font-medium text-thumbpress-title transition-colors hover:bg-gray-50'; const link = 'cursor-pointer border-0 bg-transparent p-0 text-sm text-[#64748B] underline underline-offset-2'; return (