@@ -6,17 +6,31 @@ import buildUrl from 'lib/api/buildUrl';
66import useFetch from 'lib/hooks/useFetch' ;
77import { Button } from 'toolkit/chakra/button' ;
88import { toaster } from 'toolkit/chakra/toaster' ;
9+ import { SECOND } from 'toolkit/utils/consts' ;
10+ import { apos } from 'toolkit/utils/htmlEntities' ;
911import ReCaptcha from 'ui/shared/reCaptcha/ReCaptcha' ;
1012import useReCaptcha from 'ui/shared/reCaptcha/useReCaptcha' ;
1113
1214import AppErrorIcon from '../AppErrorIcon' ;
1315import AppErrorTitle from '../AppErrorTitle' ;
1416
17+ function formatTimeLeft ( timeLeft : number ) {
18+ const hours = Math . floor ( timeLeft / 3600 ) ;
19+ const minutes = Math . floor ( ( timeLeft % 3600 ) / 60 ) ;
20+ const seconds = timeLeft % 60 ;
21+
22+ return `${ hours . toString ( ) . padStart ( 2 , '0' ) } h ${ minutes . toString ( ) . padStart ( 2 , '0' ) } m ${ seconds . toString ( ) . padStart ( 2 , '0' ) } s` ;
23+ }
24+
1525interface Props {
1626 bypassOptions ?: string ;
27+ reset ?: string ;
1728}
1829
19- const AppErrorTooManyRequests = ( { bypassOptions } : Props ) => {
30+ const AppErrorTooManyRequests = ( { bypassOptions, reset } : Props ) => {
31+
32+ const [ timeLeft , setTimeLeft ] = React . useState ( reset ? Math . ceil ( Number ( reset ) / SECOND ) : undefined ) ;
33+
2034 const fetch = useFetch ( ) ;
2135 const recaptcha = useReCaptcha ( ) ;
2236
@@ -52,19 +66,54 @@ const AppErrorTooManyRequests = ({ bypassOptions }: Props) => {
5266 }
5367 } , [ recaptcha , fetch ] ) ;
5468
69+ React . useEffect ( ( ) => {
70+ if ( reset === undefined ) {
71+ return ;
72+ }
73+
74+ const interval = window . setInterval ( ( ) => {
75+ setTimeLeft ( ( prev ) => {
76+ if ( prev && prev > 1 ) {
77+ return prev - 1 ;
78+ }
79+
80+ window . clearInterval ( interval ) ;
81+ window . location . reload ( ) ;
82+
83+ return 0 ;
84+ } ) ;
85+ } , SECOND ) ;
86+
87+ return ( ) => {
88+ window . clearInterval ( interval ) ;
89+ } ;
90+ } , [ reset ] ) ;
91+
5592 if ( ! config . services . reCaptchaV2 . siteKey ) {
5693 throw new Error ( 'reCAPTCHA V2 site key is not set' ) ;
5794 }
5895
96+ const text = ( ( ) => {
97+ if ( timeLeft === undefined && bypassOptions === 'no_bypass' ) {
98+ return 'Rate limit exceeded.' ;
99+ }
100+
101+ const timeLeftText = timeLeft !== undefined ? `wait ${ formatTimeLeft ( timeLeft ) } ` : '' ;
102+ const bypassText = bypassOptions !== 'no_bypass' ? `verify you${ apos } re human ` : '' ;
103+ const orText = timeLeft !== undefined && bypassOptions !== 'no_bypass' ? 'OR ' : '' ;
104+
105+ return `Rate limit exceeded. Please ${ timeLeftText } ${ orText } ${ bypassText } before making another request.` ;
106+ } ) ( ) ;
107+
59108 return (
60109 < >
61110 < AppErrorIcon statusCode = { 429 } />
62111 < AppErrorTitle title = "Too many requests" />
63112 < Text color = "text.secondary" mt = { 3 } >
64- You have exceeded the request rate for a given time period. Please reduce the number of requests and try again soon.
113+ { text }
65114 </ Text >
66115 < ReCaptcha { ...recaptcha } />
67- { bypassOptions !== 'no_bypass' && < Button onClick = { handleSubmit } disabled = { recaptcha . isInitError } mt = { 8 } > Try again </ Button > }
116+ { bypassOptions !== 'no_bypass' && < Button onClick = { handleSubmit } disabled = { recaptcha . isInitError } mt = { 8 } > I'm not a robot </ Button > }
68117 </ >
69118 ) ;
70119} ;
0 commit comments