refactor(captcha): simplify interval handling in hook (#10974)
Close #10708 --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1,16 +1,19 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useRequestFreshCaptchaToken } from '@/captcha/hooks/useRequestFreshCaptchaToken';
|
||||
import { isCaptchaScriptLoadedState } from '@/captcha/states/isCaptchaScriptLoadedState';
|
||||
import { getCaptchaUrlByProvider } from '@/captcha/utils/getCaptchaUrlByProvider';
|
||||
import { captchaState } from '@/client-config/states/captchaState';
|
||||
import { CaptchaDriverType } from '~/generated/graphql';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const CaptchaProviderScriptLoaderEffect = () => {
|
||||
const captcha = useRecoilValue(captchaState);
|
||||
const setIsCaptchaScriptLoaded = useSetRecoilState(
|
||||
isCaptchaScriptLoadedState,
|
||||
);
|
||||
const { requestFreshCaptchaToken } = useRequestFreshCaptchaToken();
|
||||
|
||||
useEffect(() => {
|
||||
if (!captcha?.provider || !captcha.siteKey) {
|
||||
@ -43,6 +46,29 @@ export const CaptchaProviderScriptLoaderEffect = () => {
|
||||
document.body.appendChild(scriptElement);
|
||||
}
|
||||
}, [captcha?.provider, captcha?.siteKey, setIsCaptchaScriptLoaded]);
|
||||
useEffect(() => {
|
||||
if (isUndefinedOrNull(captcha?.provider)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let refreshInterval: NodeJS.Timeout;
|
||||
|
||||
switch (captcha.provider) {
|
||||
case CaptchaDriverType.GoogleRecaptcha:
|
||||
// Google reCAPTCHA tokens expire after 120 seconds, refresh at 110 seconds
|
||||
refreshInterval = setInterval(requestFreshCaptchaToken, 110 * 1000);
|
||||
break;
|
||||
case CaptchaDriverType.Turnstile:
|
||||
// Cloudflare Turnstile tokens expire after 500 seconds, refresh at 480 seconds
|
||||
refreshInterval = setInterval(requestFreshCaptchaToken, 480 * 1000);
|
||||
break;
|
||||
default:
|
||||
// Note: hCaptcha has a callback system for expiration that we're not implementing now
|
||||
return;
|
||||
}
|
||||
|
||||
return () => clearInterval(refreshInterval);
|
||||
}, [captcha?.provider, requestFreshCaptchaToken]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { MULTI_WORKSPACE_DROPDOWN_ID } from '@/ui/navigation/navigation-drawer/constants/MultiWorkspaceDropdownId';
|
||||
import { NavigationDrawerHotKeyScope } from '@/ui/navigation/navigation-drawer/types/NavigationDrawerHotKeyScope';
|
||||
import { multiWorkspaceDropdownState } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownState';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useMemo } from 'react';
|
||||
import { MultiWorkspaceDropdownClickableComponent } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownClickableComponent';
|
||||
import { MultiWorkspaceDropdownDefaultComponents } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownDefaultComponents';
|
||||
import { MultiWorkspaceDropdownThemesComponents } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownThemesComponents';
|
||||
import { MultiWorkspaceDropdownWorkspacesListComponents } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownWorkspacesListComponents';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { MULTI_WORKSPACE_DROPDOWN_ID } from '@/ui/navigation/navigation-drawer/constants/MultiWorkspaceDropdownId';
|
||||
import { multiWorkspaceDropdownState } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownState';
|
||||
import { NavigationDrawerHotKeyScope } from '@/ui/navigation/navigation-drawer/types/NavigationDrawerHotKeyScope';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
export const MultiWorkspaceDropdownButton = () => {
|
||||
const [multiWorkspaceDropdown, setMultiWorkspaceDropdown] = useRecoilState(
|
||||
@ -26,8 +25,6 @@ export const MultiWorkspaceDropdownButton = () => {
|
||||
}
|
||||
}, [multiWorkspaceDropdown]);
|
||||
|
||||
const { isDropdownOpen } = useDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={MULTI_WORKSPACE_DROPDOWN_ID}
|
||||
@ -35,11 +32,7 @@ export const MultiWorkspaceDropdownButton = () => {
|
||||
scope: NavigationDrawerHotKeyScope.MultiWorkspaceDropdownButton,
|
||||
}}
|
||||
dropdownOffset={{ y: -35, x: -5 }}
|
||||
clickableComponent={
|
||||
<MultiWorkspaceDropdownClickableComponent
|
||||
isDropdownOpen={isDropdownOpen}
|
||||
/>
|
||||
}
|
||||
clickableComponent={<MultiWorkspaceDropdownClickableComponent />}
|
||||
dropdownComponents={<DropdownComponents />}
|
||||
onClose={() => {
|
||||
setMultiWorkspaceDropdown('default');
|
||||
|
||||
@ -11,11 +11,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
|
||||
export const MultiWorkspaceDropdownClickableComponent = ({
|
||||
isDropdownOpen,
|
||||
}: {
|
||||
isDropdownOpen?: boolean;
|
||||
}) => {
|
||||
export const MultiWorkspaceDropdownClickableComponent = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const theme = useTheme();
|
||||
|
||||
@ -36,7 +32,6 @@ export const MultiWorkspaceDropdownClickableComponent = ({
|
||||
</NavigationDrawerAnimatedCollapseWrapper>
|
||||
<NavigationDrawerAnimatedCollapseWrapper>
|
||||
<StyledIconChevronDown
|
||||
isDropdownOpen={isDropdownOpen}
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
|
||||
@ -32,12 +32,9 @@ export const StyledLabel = styled.div`
|
||||
|
||||
export const StyledIconChevronDown = styled(IconChevronDown)<{
|
||||
disabled?: boolean;
|
||||
isDropdownOpen?: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
color: ${({ disabled, theme }) =>
|
||||
disabled ? theme.font.color.extraLight : theme.font.color.tertiary};
|
||||
display: flex;
|
||||
rotate: ${({ isDropdownOpen }) => (isDropdownOpen ? '-180deg' : '0deg')};
|
||||
transition: rotate 0.1s ease-in-out;
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user