| 1 |
import Box from '@elementor/ui/Box'; |
| 2 |
import Popover from '@elementor/ui/Popover'; |
| 3 |
import Typography from '@elementor/ui/Typography'; |
| 4 |
import { styled } from '@elementor/ui/styles'; |
| 5 |
import { useEffect, useRef } from '@wordpress/element'; |
| 6 |
import { escapeHTML } from '@wordpress/escape-html'; |
| 7 |
import { __ } from '@wordpress/i18n'; |
| 8 |
import useStorage from '../hooks/use-storage'; |
| 9 |
import API from '../api'; |
| 10 |
import DismissButton from '../components/dismiss-button'; |
| 11 |
import FeedbackForm from '../components/feedback-form'; |
| 12 |
import RatingForm from '../components/rating-form'; |
| 13 |
import ReviewForm from '../components/review-form'; |
| 14 |
import { useNotifications, useSettings } from '../hooks/use-settings'; |
| 15 |
|
| 16 |
const UserFeedbackForm = ( ) => { |
| 17 |
const { success, error } = useNotifications(); |
| 18 |
const { save, get } = useStorage(); |
| 19 |
const anchorEl = useRef( null ); |
| 20 |
const { |
| 21 |
rating, |
| 22 |
setRating, |
| 23 |
feedback, |
| 24 |
isOpened, |
| 25 |
setIsOpened, |
| 26 |
setCurrentPage, |
| 27 |
} = useSettings(); |
| 28 |
|
| 29 |
useEffect( () => { |
| 30 |
/** |
| 31 |
* Show the popover if the user has not submitted repo feedback. |
| 32 |
*/ |
| 33 |
if ( window?.imageOptimizerReviewData?.reviewData?.rating > 3 && ! window?.imageOptimizerReviewData?.reviewData?.repo_review_clicked ) { |
| 34 |
setCurrentPage( 'review' ); |
| 35 |
setRating( window?.imageOptimizerReviewData?.reviewData?.rating ); // re-add the saved rating |
| 36 |
} |
| 37 |
}, [] ); |
| 38 |
|
| 39 |
/** |
| 40 |
* Close the popover. |
| 41 |
* @param {Object} event |
| 42 |
* @param {string} reason |
| 43 |
*/ |
| 44 |
const handleClose = ( event, reason ) => { |
| 45 |
if ( 'backdropClick' !== reason ) { |
| 46 |
setIsOpened( false ); |
| 47 |
} |
| 48 |
}; |
| 49 |
|
| 50 |
const id = isOpened ? 'reviews-popover' : undefined; |
| 51 |
|
| 52 |
const { currentPage } = useSettings(); |
| 53 |
|
| 54 |
const headerMessage = { |
| 55 |
ratings: __( 'How would you rate Image Optimizer so far?', 'image-optimization' ), |
| 56 |
feedback: __( 'We’re thrilled to hear that! What would make it even better?', 'image-optimization' ), |
| 57 |
review: __( "We're thrilled you're enjoying Image Optimizer", 'image-optimization' ), |
| 58 |
}; |
| 59 |
|
| 60 |
const handleSubmit = async ( close, avoidClosing = false ) => { |
| 61 |
try { |
| 62 |
const response = await API.sendFeedback( { rating, feedback } ).then( async ( res ) => { |
| 63 |
await save( { |
| 64 |
image_optimizer_review_data: { |
| 65 |
...get.data.image_optimizer_review_data, |
| 66 |
rating: parseInt( rating ), |
| 67 |
feedback: escapeHTML( feedback ), |
| 68 |
submitted: true, |
| 69 |
}, |
| 70 |
} ); |
| 71 |
|
| 72 |
return res; |
| 73 |
} ); |
| 74 |
|
| 75 |
if ( ! response?.success && parseInt( rating ) < 4 ) { |
| 76 |
/** |
| 77 |
* Show success message if the feedback was already submitted. |
| 78 |
*/ |
| 79 |
success( __( 'Feedback already submitted', 'image-optimization' ) ); |
| 80 |
} else if ( response?.success && parseInt( rating ) < 4 ) { |
| 81 |
success( __( 'Thank you for your feedback!', 'image-optimization' ) ); |
| 82 |
} |
| 83 |
|
| 84 |
if ( ! avoidClosing ) { |
| 85 |
await close(); |
| 86 |
} |
| 87 |
|
| 88 |
return true; |
| 89 |
} catch ( e ) { |
| 90 |
error( __( 'Failed to submit!', 'image-optimization' ) ); |
| 91 |
console.log( e ); |
| 92 |
return false; |
| 93 |
} |
| 94 |
}; |
| 95 |
|
| 96 |
return ( |
| 97 |
<Popover |
| 98 |
open={ isOpened } |
| 99 |
anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } } |
| 100 |
anchorReference="anchorPosition" |
| 101 |
anchorPosition={ { |
| 102 |
top: window.innerHeight - 10, |
| 103 |
left: window.innerWidth - 10, |
| 104 |
} } |
| 105 |
id={ id } |
| 106 |
onClose={ handleClose } |
| 107 |
anchorEl={ anchorEl.current } |
| 108 |
disableEscapeKeyDown |
| 109 |
disableScrollLock |
| 110 |
disablePortal |
| 111 |
slotProps={ { |
| 112 |
paper: { |
| 113 |
sx: { |
| 114 |
pointerEvents: 'auto', // allow interactions inside popover |
| 115 |
}, |
| 116 |
}, |
| 117 |
} } |
| 118 |
sx={ { |
| 119 |
pointerEvents: 'none', // allow click-through behind |
| 120 |
} } |
| 121 |
> |
| 122 |
<StyledBox> |
| 123 |
<Header> |
| 124 |
<Typography |
| 125 |
variant="subtitle1" |
| 126 |
color="text.primary" |
| 127 |
> |
| 128 |
{ headerMessage?.[ currentPage ] } |
| 129 |
</Typography> |
| 130 |
<DismissButton close={ close } /> |
| 131 |
</Header> |
| 132 |
{ 'ratings' === currentPage && <RatingForm close={ handleClose } handleSubmitForm={ handleSubmit } /> } |
| 133 |
{ 'feedback' === currentPage && <FeedbackForm close={ handleClose } handleSubmitForm={ handleSubmit } /> } |
| 134 |
{ 'review' === currentPage && <ReviewForm close={ handleClose } /> } |
| 135 |
</StyledBox> |
| 136 |
</Popover> |
| 137 |
); |
| 138 |
}; |
| 139 |
|
| 140 |
export default UserFeedbackForm; |
| 141 |
|
| 142 |
const StyledBox = styled( Box )` |
| 143 |
width: 350px; |
| 144 |
padding: ${ ( { theme } ) => theme.spacing( 1.5 ) }; |
| 145 |
`; |
| 146 |
|
| 147 |
const Header = styled( Box )` |
| 148 |
display: flex; |
| 149 |
flex-direction: row; |
| 150 |
justify-content: space-between; |
| 151 |
align-items: center; |
| 152 |
margin-bottom: ${ ( { theme } ) => theme.spacing( 2 ) }; |
| 153 |
`; |
| 154 |
|