Skip to content

Commit

Permalink
feat: add autoResetOnExpire prop
Browse files Browse the repository at this point in the history
  • Loading branch information
marsidev committed Nov 21, 2022
1 parent bc94236 commit 447f979
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 17 deletions.
42 changes: 33 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ function Widget() {

## Props

| **Prop** | **Type** | **Description** | **Required** |
| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| siteKey | `string` | Your sitekey key, get one from [here](https://developers.cloudflare.com/turnstile/get-started/). ||
| options | `object` | Widget render options. More info about this options [below](https://github.com/marsidev/react-turnstile/#render-options). | |
| scriptProps | `object` | You can customize the injected `script` tag with this prop. It allows you to add `async`, `defer`, `nonce` attributes to the script tag. You can also control whether the injected script will be added to the document body or head with `appendTo` attribute. | |
| onSuccess | `function` | Callback that is invoked upon success of the challenge. The callback is passed a token that can be validated. | |
| onExpire | `function` | Callback that is invoked when a challenge expires. | |
| onError | `function` | Callback that is invoked when there is a network error. | |
| **Prop** | **Type** | **Description** | **Required** |
| ----------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| siteKey | `string` | Your sitekey key, get one from [here](https://developers.cloudflare.com/turnstile/get-started/). ||
| options | `object` | Widget render options. More info about this options [below](https://github.com/marsidev/react-turnstile/#render-options). | |
| scriptProps | `object` | You can customize the injected `script` tag with this prop. It allows you to add `async`, `defer`, `nonce` attributes to the script tag. You can also control whether the injected script will be added to the document body or head with `appendTo` attribute. | |
| onSuccess | `function` | Callback that is invoked upon success of the challenge. The callback is passed a token that can be validated. | |
| onExpire | `function` | Callback that is invoked when a challenge expires. | |
| onError | `function` | Callback that is invoked when there is a network error. | |
| autoResetOnExpire | `boolean` | Controls whether the widget should automatically reset when it expires. If is set to `true`, you don't need to use the `onExpire` callback. Default to `true`. | |


### Render options
Expand Down Expand Up @@ -148,6 +149,8 @@ function Widget() {
}
```

> `onExpire` does not take effect unless you set `autoResetOnExpire` to `false`.
### Getting the token after solving the challenge:
```jsx
import { useState } from 'react'
Expand Down Expand Up @@ -220,7 +223,7 @@ function Widget() {
### Validating a token:
```jsx
// LoginForm.jsx
import { useRef, useState } from 'react'
import { useRef } from 'react'
import { Turnstile } from '@marsidev/react-turnstile'

export default function LoginForm() {
Expand Down Expand Up @@ -288,6 +291,27 @@ export default async function handler(request, response) {
> - by calling the `.getResponse()` method.
> - by reading the widget response input with name `cf-turnstile-response`. This one is not an option if you set `options.fieldResponse` to `false`.
### Handling widget expiring:
> By default, you don't need to handle the widget expiring, unless you set `autoResetOnExpire` to `false`.
```jsx
import { useRef } from 'react'
import { Turnstile } from '@marsidev/react-turnstile'

function Widget() {
const ref = useRef(null)

return (
<Turnstile
ref={ref}
autoResetOnExpire={false}
siteKey='1x00000000000000000000AA'
onExpire={() => ref.current?.reset()}
/>
)
}
```
## Contributing
Expand Down
8 changes: 7 additions & 1 deletion packages/example/src/components/Demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,23 @@ const Demo = () => {
setStatus('solved')
}

const onExpire = () => {
setStatus('expired')
turnstileRef.current?.reset()
}

return (
<div className='flex flex-col items-center justify-center w-full min-h-screen py-24'>
<main className='w-full max-w-[740px] flex justify-center flex-col text-white p-4 gap-2'>
<h1 className='font-semibold text-4xl mb-4'>React Turnstile Demo</h1>

<Turnstile
ref={turnstileRef}
autoResetOnExpire={false}
options={{ theme, size }}
siteKey={testingSiteKey}
onError={() => setStatus('error')}
onExpire={() => setStatus('expired')}
onExpire={onExpire}
onSuccess={onSuccess}
/>

Expand Down
23 changes: 18 additions & 5 deletions src/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ import { DEFAULT_CONTAINER_ID, DEFAULT_ONLOAD_NAME, injectTurnstileScript } from
import { RenderParameters, TurnstileInstance, TurnstileProps } from './types'

export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProps>((props, ref) => {
const { scriptOptions, options, siteKey, onSuccess, onExpire, onError, id, ...divProps } = props
const {
scriptOptions,
options,
siteKey,
onSuccess,
onExpire,
onError,
id,
autoResetOnExpire = true,
...divProps
} = props
const config = options ?? {}

const [widgetId, setWidgetId] = useState<string | undefined | null>()
Expand Down Expand Up @@ -119,11 +129,13 @@ export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProp
onError: onLoadScriptError
})

/** Once a token has been issued, it can be validated within the next 300 seconds. After 300 seconds, the token is no longer valid and another challenge needs to be solved. */
const timerId = setInterval(() => window.turnstile?.reset(), 250 * 250)
if (autoResetOnExpire) {
// expire time it's documented as 300 seconds but can happen in around 290 seconds.
const timerId = setInterval(() => window.turnstile?.reset(), 290 * 1000)

return () => {
clearInterval(timerId)
return () => {
clearInterval(timerId)
}
}
}, [configJson, scriptOptionsJson])

Expand All @@ -144,4 +156,5 @@ export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProp
})

Turnstile.displayName = 'Turnstile'

export default Turnstile
9 changes: 7 additions & 2 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ interface TurnstileBaseOptions {
}

/** Props needed for the `options` prop in the `<Turnstile />` component */
interface ComponentOptions extends TurnstileBaseOptions {
interface ComponentRenderOptions extends TurnstileBaseOptions {
/**
* The tabindex of Turnstile’s iframe for accessibility purposes.
* @default 0
Expand Down Expand Up @@ -194,11 +194,16 @@ interface TurnstileProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Custom widget render options. See {@link https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#configurations the docs} for more info about this options.
*/
options?: ComponentOptions
options?: ComponentRenderOptions
/**
* Custom injected script options.
*/
scriptOptions?: ScriptOptions
/**
* Controls whether the widget should automatically reset when it expires.
* @default true
*/
autoResetOnExpire?: boolean
}

interface InjectTurnstileScriptParams {
Expand Down

0 comments on commit 447f979

Please sign in to comment.