Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@
"submit": "Create account",
"creating": "Creating account...",
"alreadyHaveAccount": "Already have an account?",
"legal": "By creating an account you agree to the <terms>Terms</terms> and <privacy>Privacy</privacy> policy.",
"errors": {
"failed": "Registration failed."
},
Expand Down Expand Up @@ -1039,6 +1040,8 @@
"twitter": "X / Twitter",
"legal": "Legal",
"license": "License (Apache-2.0)",
"terms": "Terms",
"privacy": "Privacy",
"copyright": "© {{year}} Commonly. Code licensed under Apache-2.0; the Commonly name and logo are trademarks of the Commonly project."
}
},
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@
"submit": "注册",
"creating": "正在注册…",
"alreadyHaveAccount": "已有账号?",
"legal": "创建账号即表示你同意<terms>服务条款</terms>和<privacy>隐私政策</privacy>。",
"errors": {
"failed": "注册失败。"
},
Expand Down Expand Up @@ -1038,6 +1039,8 @@
"twitter": "X / Twitter",
"legal": "法律信息",
"license": "许可证(Apache-2.0)",
"terms": "服务条款",
"privacy": "隐私政策",
"copyright": "© {{year}} Commonly。代码采用 Apache-2.0 许可;Commonly 名称和标志是 Commonly 项目的商标。"
}
},
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/v2/__tests__/V2Register.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,16 @@ describe('V2Register invite code handoff', () => {
expect(body.invitationCode).toBe('CM-KEPT');
});
});

// Launch row 2: signup links the Terms and Privacy pages it asks people to agree to.
describe('V2Register legal links', () => {
beforeEach(() => {
axios.get.mockResolvedValue({ data: { inviteOnly: false, providers: [] } });
});

it('links Terms and Privacy under the form', async () => {
renderRegister();
expect(await screen.findByRole('link', { name: 'Terms' })).toHaveAttribute('href', '/terms');
expect(screen.getByRole('link', { name: 'Privacy' })).toHaveAttribute('href', '/privacy');
});
});
10 changes: 10 additions & 0 deletions frontend/src/v2/components/V2Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,16 @@ const V2Register: React.FC = () => {

<V2OAuthButtons invite={invitationCode || undefined} next={nextPath} />

<div className="v2-login__hint">
<Trans
i18nKey="auth.register.legal"
components={{
terms: <Link to="/terms" className="v2-login__link" />,
privacy: <Link to="/privacy" className="v2-login__link" />,
}}
/>
</div>

<div className="v2-login__hint">
{t('auth.register.alreadyHaveAccount')}
{' '}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/v2/landing/V2LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,8 @@ const V2LandingPage: React.FC = () => {
<div className="v2-landing__footer-col">
<div className="v2-landing__footer-title">{t('landing.footer.legal')}</div>
<a className="v2-landing__footer-link" href={`${REPO}/blob/main/LICENSE`} target="_blank" rel="noreferrer">{t('landing.footer.license')}</a>
<Link className="v2-landing__footer-link" to="/terms">{t('landing.footer.terms')}</Link>
<Link className="v2-landing__footer-link" to="/privacy">{t('landing.footer.privacy')}</Link>
</div>
</div>
{/* Copyright is retained under Apache-2.0 — the license grants
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/v2/landing/__tests__/landingLegalLinks.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { render, screen, within } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import axios from 'axios';
import i18n from '../../../i18n';
import { useAuth } from '../../../context/AuthContext';
import V2LandingPage from '../V2LandingPage';

/**
* Launch row 2. /terms and /privacy shipped with no link reaching them; the
* footer's Legal column is where a visitor looks for both.
*/

jest.mock('axios');
jest.mock('../../../context/AuthContext', () => ({
useAuth: jest.fn(),
}));

describe('V2LandingPage legal links', () => {
beforeEach(async () => {
(axios.get as jest.Mock).mockResolvedValue({ data: {} });
(useAuth as jest.Mock).mockReturnValue({ isAuthenticated: false });
await i18n.changeLanguage('en');
});

afterEach(() => jest.clearAllMocks());

it('links Terms and Privacy from the footer', () => {
const { container } = render(<MemoryRouter><V2LandingPage /></MemoryRouter>);
const footer = container.querySelector('footer') as HTMLElement;
expect(within(footer).getByRole('link', { name: 'Terms' })).toHaveAttribute('href', '/terms');
expect(within(footer).getByRole('link', { name: 'Privacy' })).toHaveAttribute('href', '/privacy');
});
});
Loading