mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
refactor(ui): refactor terms of use (#603)
* refactor(ui): refactor terms of use refactor terms of use * fix(ui): fix terms modal fix terms mdoal * fix(ui): cr fix remove console.log
This commit is contained in:
parent
e4e3fd409e
commit
3d8c3af5bd
21 changed files with 241 additions and 141 deletions
|
@ -37,6 +37,7 @@ const translation = {
|
|||
loading: 'Loading...',
|
||||
redirecting: 'Redirecting...',
|
||||
agree_with_terms: 'I have read and agree to the ',
|
||||
agree_with_terms_modal: 'Please read the {{terms}} and then agree the box first.',
|
||||
terms_of_use: 'Terms of Use',
|
||||
create_account: 'Create Account',
|
||||
forgot_password: 'Forgot Password?',
|
||||
|
|
|
@ -39,6 +39,7 @@ const translation = {
|
|||
loading: '读取中...',
|
||||
redirecting: '页面跳转中...',
|
||||
agree_with_terms: '我已阅读并同意 ',
|
||||
agree_with_terms_modal: 'Please read the {{terms}} and then agree the box first.',
|
||||
terms_of_use: '使用条款',
|
||||
create_account: '创建账号',
|
||||
forgot_password: '忘记密码?',
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { useContext, useEffect, ReactElement } from 'react';
|
||||
|
||||
import { PageContext } from '@/hooks/use-page-context';
|
||||
import { SignInExperienceSettings } from '@/types';
|
||||
|
||||
type Props = {
|
||||
settings: SignInExperienceSettings;
|
||||
children: ReactElement;
|
||||
};
|
||||
|
||||
const SettingsProvider = ({ settings, children }: Props) => {
|
||||
const { setExperienceSettings } = useContext(PageContext);
|
||||
|
||||
useEffect(() => {
|
||||
setExperienceSettings(settings);
|
||||
}, [setExperienceSettings, settings]);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
export default SettingsProvider;
|
|
@ -1,3 +1,8 @@
|
|||
import { Language } from '@logto/phrases';
|
||||
import { BrandingStyle, SignInExperience, SignInMethodState } from '@logto/schemas';
|
||||
|
||||
import { SignInExperienceSettings } from '@/types';
|
||||
|
||||
export const appLogo = 'https://avatars.githubusercontent.com/u/88327661?s=200&v=4';
|
||||
export const appHeadline = 'Build user identity in a modern way';
|
||||
export const socialConnectors = [
|
||||
|
@ -38,29 +43,38 @@ export const socialConnectors = [
|
|||
},
|
||||
];
|
||||
|
||||
export const mockSignInExperience = {
|
||||
export const mockSignInExperience: SignInExperience = {
|
||||
id: 'foo',
|
||||
branding: {
|
||||
primaryColor: '#000',
|
||||
isDarkModeEnabled: true,
|
||||
darkPrimaryColor: '#fff',
|
||||
style: 'Logo_Slogan',
|
||||
style: BrandingStyle.Logo_Slogan,
|
||||
logoUrl: 'http://logto.png',
|
||||
slogan: 'logto',
|
||||
},
|
||||
termsOfUse: {
|
||||
enabled: false,
|
||||
enabled: true,
|
||||
contentUrl: 'http://terms.of.use',
|
||||
},
|
||||
languageInfo: {
|
||||
autoDetect: true,
|
||||
fallbackLanguage: 'en',
|
||||
fixedLanguage: 'zh-cn',
|
||||
fallbackLanguage: Language.English,
|
||||
fixedLanguage: Language.Chinese,
|
||||
},
|
||||
signInMethods: {
|
||||
username: 'primary',
|
||||
email: 'secondary',
|
||||
sms: 'secondary',
|
||||
social: 'secondary',
|
||||
username: SignInMethodState.Primary,
|
||||
email: SignInMethodState.Secondary,
|
||||
sms: SignInMethodState.Secondary,
|
||||
social: SignInMethodState.Secondary,
|
||||
},
|
||||
socialSignInConnectorIds: ['github', 'facebook'],
|
||||
};
|
||||
|
||||
export const mockSignInExperienceSettings: SignInExperienceSettings = {
|
||||
branding: mockSignInExperience.branding,
|
||||
termsOfUse: mockSignInExperience.termsOfUse,
|
||||
languageInfo: mockSignInExperience.languageInfo,
|
||||
primarySignInMethod: 'username',
|
||||
secondarySignInMethods: ['email', 'sms', 'social'],
|
||||
};
|
||||
|
|
|
@ -36,6 +36,7 @@ const ConfirmModal = ({
|
|||
className={classNames(modalStyles.modal, className)}
|
||||
overlayClassName={modalStyles.overlay}
|
||||
parentSelector={() => document.querySelector('main') ?? document.body}
|
||||
ariaHideApp={false}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>{children}</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { TermsOfUse as TermsOfUseType } from '@logto/schemas';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -7,10 +6,7 @@ import TermsOfUse from '.';
|
|||
|
||||
describe('Terms of Use', () => {
|
||||
const onChange = jest.fn();
|
||||
const termsOfUse: TermsOfUseType = {
|
||||
enabled: true,
|
||||
contentUrl: 'http://logto.dev/',
|
||||
};
|
||||
const contentUrl = 'http://logto.dev/';
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
const prefix = t('description.agree_with_terms');
|
||||
|
||||
|
@ -20,7 +16,7 @@ describe('Terms of Use', () => {
|
|||
|
||||
it('render Terms of User checkbox', () => {
|
||||
const { getByText, container } = render(
|
||||
<TermsOfUse name="terms" termsOfUse={termsOfUse} onChange={onChange} />
|
||||
<TermsOfUse name="terms" termsUrl={contentUrl} onChange={onChange} />
|
||||
);
|
||||
|
||||
const element = getByText(prefix);
|
||||
|
@ -33,15 +29,7 @@ describe('Terms of Use', () => {
|
|||
expect(linkElement).not.toBeNull();
|
||||
|
||||
if (linkElement) {
|
||||
expect(linkElement.href).toEqual(termsOfUse.contentUrl);
|
||||
expect(linkElement.href).toEqual(contentUrl);
|
||||
}
|
||||
});
|
||||
|
||||
it('render null with disabled terms', () => {
|
||||
const { container } = render(
|
||||
<TermsOfUse name="terms" termsOfUse={{ ...termsOfUse, enabled: false }} onChange={onChange} />
|
||||
);
|
||||
|
||||
expect(container.children).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { TermsOfUse as TermsOfUseType } from '@logto/schemas';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ErrorMessage, { ErrorType } from '@/components/ErrorMessage';
|
||||
import { RadioButtonIcon } from '@/components/Icons';
|
||||
import TextLink from '@/components/TextLink';
|
||||
|
||||
|
@ -11,46 +10,39 @@ import * as styles from './index.module.scss';
|
|||
type Props = {
|
||||
name: string;
|
||||
className?: string;
|
||||
termsOfUse: TermsOfUseType;
|
||||
termsUrl: string;
|
||||
isChecked?: boolean;
|
||||
error?: ErrorType;
|
||||
onChange: (checked: boolean) => void;
|
||||
};
|
||||
|
||||
const TermsOfUse = ({ name, className, termsOfUse, isChecked, error, onChange }: Props) => {
|
||||
const TermsOfUse = ({ name, className, termsUrl, isChecked, onChange }: Props) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
|
||||
if (!termsOfUse.enabled || !termsOfUse.contentUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const prefix = t('description.agree_with_terms');
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div
|
||||
className={styles.terms}
|
||||
onClick={() => {
|
||||
onChange(!isChecked);
|
||||
}}
|
||||
>
|
||||
<input disabled readOnly name={name} type="checkbox" checked={isChecked} />
|
||||
<RadioButtonIcon checked={isChecked} className={styles.radioButton} />
|
||||
<div className={styles.content}>
|
||||
{prefix}
|
||||
<TextLink
|
||||
className={styles.link}
|
||||
text="description.terms_of_use"
|
||||
href={termsOfUse.contentUrl}
|
||||
type="secondary"
|
||||
onClick={(event) => {
|
||||
// Prevent above parent onClick event being triggered
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(styles.terms, className)}
|
||||
onClick={() => {
|
||||
onChange(!isChecked);
|
||||
}}
|
||||
>
|
||||
<input disabled readOnly name={name} type="checkbox" checked={isChecked} />
|
||||
<RadioButtonIcon checked={isChecked} className={styles.radioButton} />
|
||||
<div className={styles.content}>
|
||||
{prefix}
|
||||
<TextLink
|
||||
className={styles.link}
|
||||
text="description.terms_of_use"
|
||||
href={termsUrl}
|
||||
target="_blank"
|
||||
type="secondary"
|
||||
onClick={(event) => {
|
||||
// Prevent above parent onClick event being triggered
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{error && <ErrorMessage error={error} className={styles.errorMessage} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
22
packages/ui/src/components/TermsOfUseModal/index.test.tsx
Normal file
22
packages/ui/src/components/TermsOfUseModal/index.test.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import TermsOfUseModal from '.';
|
||||
|
||||
describe('TermsOfUseModal', () => {
|
||||
const onConfirm = jest.fn();
|
||||
const onCancel = jest.fn();
|
||||
|
||||
it('render properly', () => {
|
||||
const { queryByText } = render(
|
||||
<TermsOfUseModal
|
||||
isOpen
|
||||
termsUrl="https://www.google.com"
|
||||
onConfirm={onConfirm}
|
||||
onClose={onCancel}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(queryByText('description.agree_with_terms_modal')).not.toBeNull();
|
||||
});
|
||||
});
|
32
packages/ui/src/components/TermsOfUseModal/index.tsx
Normal file
32
packages/ui/src/components/TermsOfUseModal/index.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import reactStringReplace from 'react-string-replace';
|
||||
|
||||
import ConfirmModal from '../ConfirmModal';
|
||||
import TextLink from '../TextLink';
|
||||
|
||||
type Props = {
|
||||
isOpen?: boolean;
|
||||
onConfirm: () => void;
|
||||
onClose: () => void;
|
||||
termsUrl: string;
|
||||
};
|
||||
|
||||
const TermsOfUseModal = ({ isOpen = false, termsUrl, onConfirm, onClose }: Props) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
|
||||
const terms = t('description.terms_of_use');
|
||||
const content = t('description.agree_with_terms_modal', { terms });
|
||||
|
||||
const modalContent: ReactNode = reactStringReplace(content, terms, () => (
|
||||
<TextLink key={terms} text="description.terms_of_use" href={termsUrl} target="_blank" />
|
||||
));
|
||||
|
||||
return (
|
||||
<ConfirmModal isOpen={isOpen} onConfirm={onConfirm} onClose={onClose}>
|
||||
{modalContent}
|
||||
</ConfirmModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default TermsOfUseModal;
|
|
@ -1,23 +1,21 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { ReactNode } from 'react';
|
||||
import React, { ReactNode, AnchorHTMLAttributes } from 'react';
|
||||
import { TFuncKey, useTranslation } from 'react-i18next';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
export type Props = {
|
||||
export type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
text?: TFuncKey<'translation', 'main_flow'>;
|
||||
href?: string;
|
||||
type?: 'primary' | 'secondary';
|
||||
onClick?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||
};
|
||||
|
||||
const TextLink = ({ className, children, text, href, type = 'primary', onClick }: Props) => {
|
||||
const TextLink = ({ className, children, text, type = 'primary', ...rest }: Props) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
|
||||
return (
|
||||
<a className={classNames(styles.link, styles[type], className)} href={href} onClick={onClick}>
|
||||
<a className={classNames(styles.link, styles[type], className)} {...rest} rel="noreferrer">
|
||||
{children ?? (text ? t(text) : '')}
|
||||
</a>
|
||||
);
|
||||
|
|
|
@ -131,38 +131,6 @@ describe('<CreateAccount/>', () => {
|
|||
expect(queryByText('passwords_do_not_match')).toBeNull();
|
||||
});
|
||||
|
||||
test('terms of use not checked should throw', () => {
|
||||
const { queryByText, getByText, container } = renderWithPageContext(<CreateAccount />);
|
||||
const submitButton = getByText('action.create');
|
||||
const passwordInput = container.querySelector('input[name="password"]');
|
||||
const confirmPasswordInput = container.querySelector('input[name="confirm_password"]');
|
||||
const usernameInput = container.querySelector('input[name="username"]');
|
||||
|
||||
if (usernameInput) {
|
||||
fireEvent.change(usernameInput, { target: { value: 'username' } });
|
||||
}
|
||||
|
||||
if (passwordInput) {
|
||||
fireEvent.change(passwordInput, { target: { value: '123456' } });
|
||||
}
|
||||
|
||||
if (confirmPasswordInput) {
|
||||
fireEvent.change(confirmPasswordInput, { target: { value: '123456' } });
|
||||
}
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
expect(queryByText('agree_terms_required')).not.toBeNull();
|
||||
|
||||
expect(register).not.toBeCalled();
|
||||
|
||||
// Clear Error
|
||||
const termsButton = getByText('description.agree_with_terms');
|
||||
fireEvent.click(termsButton);
|
||||
|
||||
expect(queryByText('agree_terms_required')).toBeNull();
|
||||
});
|
||||
|
||||
test('submit form properly', async () => {
|
||||
const { getByText, container } = renderWithPageContext(<CreateAccount />);
|
||||
const submitButton = getByText('action.create');
|
||||
|
|
|
@ -211,9 +211,8 @@ const CreateAccount = ({ className }: Props) => {
|
|||
<TermsOfUse
|
||||
name="termsAgreement"
|
||||
className={styles.terms}
|
||||
termsOfUse={{ enabled: true, contentUrl: '/' }}
|
||||
termsUrl="/"
|
||||
isChecked={fieldState.termsAgreement}
|
||||
error={fieldErrors.termsAgreement}
|
||||
onChange={(checked) => {
|
||||
setFieldState((state) => ({ ...state, termsAgreement: checked }));
|
||||
}}
|
||||
|
|
|
@ -50,24 +50,7 @@ describe('<EmailPasswordless/>', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('required terms of agreement with error message', () => {
|
||||
const { queryByText, container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<EmailPasswordless type="sign-in" />
|
||||
</MemoryRouter>
|
||||
);
|
||||
const submitButton = getByText('action.continue');
|
||||
const emailInput = container.querySelector('input[name="email"]');
|
||||
|
||||
if (emailInput) {
|
||||
fireEvent.change(emailInput, { target: { value: 'foo@logto.io' } });
|
||||
}
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
expect(queryByText('agree_terms_required')).not.toBeNull();
|
||||
});
|
||||
|
||||
test('signin method properly', async () => {
|
||||
test('should call sign-in method properly', async () => {
|
||||
const { container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<EmailPasswordless type="sign-in" />
|
||||
|
@ -90,7 +73,7 @@ describe('<EmailPasswordless/>', () => {
|
|||
expect(sendSignInEmailPasscode).toBeCalledWith('foo@logto.io');
|
||||
});
|
||||
|
||||
test('register method properly', async () => {
|
||||
test('should call register method properly', async () => {
|
||||
const { container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<EmailPasswordless type="register" />
|
||||
|
|
|
@ -140,9 +140,8 @@ const EmailPasswordless = ({ type, className }: Props) => {
|
|||
<TermsOfUse
|
||||
name="termsAgreement"
|
||||
className={styles.terms}
|
||||
termsOfUse={{ enabled: true, contentUrl: '/' }}
|
||||
termsUrl="/"
|
||||
isChecked={fieldState.termsAgreement}
|
||||
error={fieldErrors.termsAgreement}
|
||||
onChange={(checked) => {
|
||||
setFieldState((state) => ({ ...state, termsAgreement: checked }));
|
||||
}}
|
||||
|
|
|
@ -53,24 +53,7 @@ describe('<PhonePasswordless/>', () => {
|
|||
}
|
||||
});
|
||||
|
||||
test('required terms of agreement with error message', () => {
|
||||
const { queryByText, container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<PhonePasswordless type="sign-in" />
|
||||
</MemoryRouter>
|
||||
);
|
||||
const submitButton = getByText('action.continue');
|
||||
const phoneInput = container.querySelector('input[name="phone"]');
|
||||
|
||||
if (phoneInput) {
|
||||
fireEvent.change(phoneInput, { target: { value: phoneNumber } });
|
||||
}
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
expect(queryByText('agree_terms_required')).not.toBeNull();
|
||||
});
|
||||
|
||||
test('signin method properly', async () => {
|
||||
test('should call sign-in method properly', async () => {
|
||||
const { container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<PhonePasswordless type="sign-in" />
|
||||
|
@ -93,7 +76,7 @@ describe('<PhonePasswordless/>', () => {
|
|||
expect(sendSignInSmsPasscode).toBeCalledWith(`${defaultCountryCallingCode}${phoneNumber}`);
|
||||
});
|
||||
|
||||
test('register method properly', async () => {
|
||||
test('should call register method properly', async () => {
|
||||
const { container, getByText } = renderWithPageContext(
|
||||
<MemoryRouter>
|
||||
<PhonePasswordless type="register" />
|
||||
|
|
|
@ -143,9 +143,8 @@ const PhonePasswordless = ({ type, className }: Props) => {
|
|||
<TermsOfUse
|
||||
name="termsAgreement"
|
||||
className={styles.terms}
|
||||
termsOfUse={{ enabled: true, contentUrl: '/' }}
|
||||
termsUrl="/"
|
||||
isChecked={fieldState.termsAgreement}
|
||||
error={fieldErrors.termsAgreement}
|
||||
onChange={(checked) => {
|
||||
setFieldState((state) => ({ ...state, termsAgreement: checked }));
|
||||
}}
|
||||
|
|
45
packages/ui/src/containers/TermsOfUse/index.tsx
Normal file
45
packages/ui/src/containers/TermsOfUse/index.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
import React from 'react';
|
||||
|
||||
import PureTermsOfUse from '@/components/TermsOfUse';
|
||||
import TermsOfUseModal from '@/components/TermsOfUseModal';
|
||||
import useTerms from '@/hooks/use-terms';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const TermsOfUse = ({ className }: Props) => {
|
||||
const { termsAgreement, setTermsAgreement, termsSettings, showTermsModal, setShowTermsModal } =
|
||||
useTerms();
|
||||
|
||||
if (!termsSettings?.enabled || !termsSettings.contentUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PureTermsOfUse
|
||||
className={className}
|
||||
name="termsAgreement"
|
||||
termsUrl={termsSettings.contentUrl}
|
||||
isChecked={termsAgreement}
|
||||
onChange={(checked) => {
|
||||
setTermsAgreement(checked);
|
||||
}}
|
||||
/>
|
||||
<TermsOfUseModal
|
||||
isOpen={showTermsModal}
|
||||
termsUrl={termsSettings.contentUrl}
|
||||
onConfirm={() => {
|
||||
setTermsAgreement(true);
|
||||
setShowTermsModal(false);
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowTermsModal(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TermsOfUse;
|
24
packages/ui/src/containers/TermsOfUse/intext.test.tsx
Normal file
24
packages/ui/src/containers/TermsOfUse/intext.test.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
|
||||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
|
||||
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
|
||||
import { mockSignInExperienceSettings } from '@/__mocks__/logto';
|
||||
|
||||
import TermsOfUse from '.';
|
||||
|
||||
describe('TermsOfUse Container', () => {
|
||||
it('render with empty TermsOfUse settings', () => {
|
||||
const { queryByText } = renderWithPageContext(<TermsOfUse />);
|
||||
expect(queryByText('description.agree_with_terms')).toBeNull();
|
||||
});
|
||||
|
||||
it('render with settings', async () => {
|
||||
const { queryByText } = renderWithPageContext(
|
||||
<SettingsProvider settings={mockSignInExperienceSettings}>
|
||||
<TermsOfUse />
|
||||
</SettingsProvider>
|
||||
);
|
||||
|
||||
expect(queryByText('description.agree_with_terms')).not.toBeNull();
|
||||
});
|
||||
});
|
|
@ -44,7 +44,6 @@ describe('<UsernameSignin>', () => {
|
|||
fireEvent.click(submitButton);
|
||||
|
||||
expect(queryByText('required')).toBeNull();
|
||||
expect(queryByText('agree_terms_required')).not.toBeNull();
|
||||
|
||||
expect(signInBasic).not.toBeCalled();
|
||||
});
|
||||
|
|
|
@ -168,9 +168,8 @@ const UsernameSignin = ({ className }: Props) => {
|
|||
<TermsOfUse
|
||||
name="termsAgreement"
|
||||
className={styles.terms}
|
||||
termsOfUse={{ enabled: true, contentUrl: '/' }}
|
||||
termsUrl="/"
|
||||
isChecked={fieldState.termsAgreement}
|
||||
error={fieldErrors.termsAgreement}
|
||||
onChange={(checked) => {
|
||||
setFieldState((state) => ({ ...state, termsAgreement: checked }));
|
||||
}}
|
||||
|
|
32
packages/ui/src/hooks/use-terms.ts
Normal file
32
packages/ui/src/hooks/use-terms.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { useContext, useCallback } from 'react';
|
||||
|
||||
import { PageContext } from './use-page-context';
|
||||
|
||||
const useTerms = () => {
|
||||
const {
|
||||
termsAgreement,
|
||||
setTermsAgreement,
|
||||
showTermsModal,
|
||||
setShowTermsModal,
|
||||
experienceSettings,
|
||||
} = useContext(PageContext);
|
||||
|
||||
const termsValidation = useCallback(() => {
|
||||
if (termsAgreement) {
|
||||
return;
|
||||
}
|
||||
|
||||
setShowTermsModal(true);
|
||||
}, [setShowTermsModal, termsAgreement]);
|
||||
|
||||
return {
|
||||
termsSettings: experienceSettings?.termsOfUse,
|
||||
termsAgreement,
|
||||
showTermsModal,
|
||||
termsValidation,
|
||||
setTermsAgreement,
|
||||
setShowTermsModal,
|
||||
};
|
||||
};
|
||||
|
||||
export default useTerms;
|
Loading…
Reference in a new issue