9 changed files with 144 additions and 13 deletions
@ -0,0 +1,81 @@ |
|||||||
|
import Turnstile, { BoundTurnstileObject } from "react-turnstile"; |
||||||
|
import { create } from "zustand"; |
||||||
|
import { immer } from "zustand/middleware/immer"; |
||||||
|
|
||||||
|
import { conf } from "@/setup/config"; |
||||||
|
|
||||||
|
export interface TurnstileStore { |
||||||
|
turnstile: BoundTurnstileObject | null; |
||||||
|
cbs: ((token: string | null) => void)[]; |
||||||
|
setTurnstile(v: BoundTurnstileObject | null): void; |
||||||
|
getToken(): Promise<string>; |
||||||
|
processToken(token: string | null): void; |
||||||
|
} |
||||||
|
|
||||||
|
export const useTurnstileStore = create( |
||||||
|
immer<TurnstileStore>((set, get) => ({ |
||||||
|
turnstile: null, |
||||||
|
cbs: [], |
||||||
|
processToken(token) { |
||||||
|
const cbs = get().cbs; |
||||||
|
cbs.forEach((fn) => fn(token)); |
||||||
|
set((s) => { |
||||||
|
s.cbs = []; |
||||||
|
}); |
||||||
|
}, |
||||||
|
getToken() { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
set((s) => { |
||||||
|
s.cbs = [ |
||||||
|
...s.cbs, |
||||||
|
(token) => { |
||||||
|
if (!token) reject(new Error("Failed to get token")); |
||||||
|
else resolve(token); |
||||||
|
}, |
||||||
|
]; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
setTurnstile(v) { |
||||||
|
set((s) => { |
||||||
|
s.turnstile = v; |
||||||
|
}); |
||||||
|
}, |
||||||
|
})) |
||||||
|
); |
||||||
|
|
||||||
|
export function getTurnstile() { |
||||||
|
return useTurnstileStore.getState().turnstile; |
||||||
|
} |
||||||
|
|
||||||
|
export function isTurnstileInitialized() { |
||||||
|
return !!getTurnstile(); |
||||||
|
} |
||||||
|
|
||||||
|
export function getTurnstileToken() { |
||||||
|
const turnstile = getTurnstile(); |
||||||
|
turnstile?.reset(); |
||||||
|
turnstile?.execute(); |
||||||
|
return useTurnstileStore.getState().getToken(); |
||||||
|
} |
||||||
|
|
||||||
|
export function TurnstileProvider() { |
||||||
|
const siteKey = conf().TURNSTILE_KEY; |
||||||
|
const setTurnstile = useTurnstileStore((s) => s.setTurnstile); |
||||||
|
const processToken = useTurnstileStore((s) => s.processToken); |
||||||
|
if (!siteKey) return null; |
||||||
|
return ( |
||||||
|
<Turnstile |
||||||
|
sitekey={siteKey} |
||||||
|
onLoad={(_widgetId, bound) => { |
||||||
|
setTurnstile(bound); |
||||||
|
}} |
||||||
|
onError={() => { |
||||||
|
processToken(null); |
||||||
|
}} |
||||||
|
onVerify={(token) => { |
||||||
|
processToken(token); |
||||||
|
}} |
||||||
|
/> |
||||||
|
); |
||||||
|
} |
Loading…
Reference in new issue