@@ -10,6 +10,12 @@ import { ButtonStyle } from "widgets/ButtonWidget";
1010import { Theme , darkenHover , darkenActive } from "constants/DefaultTheme" ;
1111import _ from "lodash" ;
1212import { ComponentProps } from "components/designSystems/appsmith/BaseComponent" ;
13+ import useScript from "utils/hooks/useScript" ;
14+ import { AppToaster } from "components/editorComponents/ToastComponent" ;
15+ import {
16+ GOOGLE_RECAPTCHA_KEY_ERROR ,
17+ GOOGLE_RECAPTCHA_DOMAIN_ERROR ,
18+ } from "constants/messages" ;
1319
1420const getButtonColorStyles = ( props : { theme : Theme } & ButtonStyleProps ) => {
1521 if ( props . filled ) return props . theme . colors . textOnDarkBG ;
@@ -124,6 +130,11 @@ export enum ButtonType {
124130 BUTTON = "button" ,
125131}
126132
133+ interface RecaptchaProps {
134+ googleRecaptchaKey ?: string ;
135+ clickWithRecaptcha : ( token : string ) => void ;
136+ }
137+
127138interface ButtonContainerProps extends ComponentProps {
128139 text ?: string ;
129140 icon ?: MaybeElement ;
@@ -148,20 +159,82 @@ const mapButtonStyleToStyleName = (buttonStyle?: ButtonStyle) => {
148159 }
149160} ;
150161
162+ const RecaptchaComponent = (
163+ props : {
164+ children : any ;
165+ onClick ?: ( event : React . MouseEvent < HTMLElement > ) => void ;
166+ } & RecaptchaProps ,
167+ ) => {
168+ function handleError ( event : React . MouseEvent < HTMLElement > , error : string ) {
169+ AppToaster . show ( {
170+ message : error ,
171+ type : "error" ,
172+ } ) ;
173+ props . onClick && props . onClick ( event ) ;
174+ }
175+ const status = useScript (
176+ `https://www.google.com/recaptcha/api.js?render=${ props . googleRecaptchaKey } ` ,
177+ ) ;
178+ return (
179+ < div
180+ onClick = { ( event : React . MouseEvent < HTMLElement > ) => {
181+ if ( status === "ready" ) {
182+ ( window as any ) . grecaptcha . ready ( ( ) => {
183+ try {
184+ ( window as any ) . grecaptcha
185+ . execute ( props . googleRecaptchaKey , { action : "submit" } )
186+ . then ( ( token : any ) => {
187+ props . clickWithRecaptcha ( token ) ;
188+ } )
189+ . catch ( ( ) => {
190+ // Handle corrent key with wrong
191+ handleError ( event , GOOGLE_RECAPTCHA_KEY_ERROR ) ;
192+ } ) ;
193+ } catch ( ex ) {
194+ // Handle wrong key
195+ handleError ( event , GOOGLE_RECAPTCHA_DOMAIN_ERROR ) ;
196+ }
197+ } ) ;
198+ }
199+ } }
200+ >
201+ { props . children }
202+ </ div >
203+ ) ;
204+ } ;
205+
206+ const BtnWrapper = (
207+ props : {
208+ children : any ;
209+ onClick ?: ( event : React . MouseEvent < HTMLElement > ) => void ;
210+ } & RecaptchaProps ,
211+ ) => {
212+ if ( ! props . googleRecaptchaKey )
213+ return < div onClick = { props . onClick } > { props . children } </ div > ;
214+ return < RecaptchaComponent { ...props } > </ RecaptchaComponent > ;
215+ } ;
216+
151217// To be used with the canvas
152- const ButtonContainer = ( props : ButtonContainerProps & ButtonStyleProps ) => {
218+ const ButtonContainer = (
219+ props : ButtonContainerProps & ButtonStyleProps & RecaptchaProps ,
220+ ) => {
153221 return (
154- < BaseButton
155- loading = { props . isLoading }
156- icon = { props . icon }
157- rightIcon = { props . rightIcon }
158- text = { props . text }
159- filled = { props . buttonStyle !== "SECONDARY_BUTTON" }
160- accent = { mapButtonStyleToStyleName ( props . buttonStyle ) }
222+ < BtnWrapper
223+ googleRecaptchaKey = { props . googleRecaptchaKey }
224+ clickWithRecaptcha = { props . clickWithRecaptcha }
161225 onClick = { props . onClick }
162- disabled = { props . disabled }
163- type = { props . type }
164- />
226+ >
227+ < BaseButton
228+ loading = { props . isLoading }
229+ icon = { props . icon }
230+ rightIcon = { props . rightIcon }
231+ text = { props . text }
232+ filled = { props . buttonStyle !== "SECONDARY_BUTTON" }
233+ accent = { mapButtonStyleToStyleName ( props . buttonStyle ) }
234+ disabled = { props . disabled }
235+ type = { props . type }
236+ />
237+ </ BtnWrapper >
165238 ) ;
166239} ;
167240
0 commit comments