Skip to content

Commit c5f0804

Browse files
committed
feat: Require consent for oauth sign up too
https://harperdb.atlassian.net/browse/STUDIO-654
1 parent a8caff7 commit c5f0804

File tree

3 files changed

+107
-52
lines changed

3 files changed

+107
-52
lines changed

src/features/auth/SignUp.tsx

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { zodRequireEmail } from '@/lib/zod/email';
1313
import { zodRequirePassword } from '@/lib/zod/password';
1414
import { zodResolver } from '@hookform/resolvers/zod';
1515
import { Link, useNavigate, useSearch } from '@tanstack/react-router';
16-
import { useCallback, useEffect } from 'react';
16+
import { MouseEvent, useCallback, useEffect, useState } from 'react';
1717
import { useForm } from 'react-hook-form';
1818
import { z } from 'zod';
1919
import { GitHubAuthenticationButton } from './components/GitHubAuthenticationButton';
@@ -56,6 +56,8 @@ const SignUpSchema = z.object({
5656
export function SignUp() {
5757
const navigate = useNavigate();
5858
const { email: searchEmail, me: formPersistenceEmail } = useSearch({ strict: false });
59+
const [flashTerms, setFlashTerms] = useState(false);
60+
5961
const methods = useForm({
6062
resolver: zodResolver(SignUpSchema),
6163
defaultValues: {
@@ -69,6 +71,7 @@ export function SignUp() {
6971
});
7072

7173
const email = methods.watch('email');
74+
const acceptTerms = methods.watch('acceptTerms');
7275
const { setFocus, control, handleSubmit } = methods;
7376

7477
useEffect(() => {
@@ -95,18 +98,82 @@ export function SignUp() {
9598
});
9699
}, [navigate, submitSignUpData]);
97100

101+
const onOAuthClick = useCallback((e: MouseEvent) => {
102+
if (!acceptTerms) {
103+
setFlashTerms(true);
104+
setTimeout(() => setFlashTerms(false), 1000);
105+
e.preventDefault();
106+
return false;
107+
}
108+
}, [acceptTerms]);
109+
110+
const termsCheckbox = (
111+
<FormField
112+
control={control}
113+
name="acceptTerms"
114+
render={({ field }) => (
115+
<FormItem
116+
className={`flex flex-row items-start space-x-3 space-y-0 p-1 transition-colors duration-300 ${
117+
flashTerms ? 'bg-red-500/20 animate-pulse rounded' : ''
118+
}`}
119+
>
120+
<FormControl>
121+
<Input
122+
type="checkbox"
123+
className="size-4 rounded border-gray-300 bg-white text-purple-600 focus:ring-purple-500"
124+
checked={field.value}
125+
onChange={field.onChange}
126+
/>
127+
</FormControl>
128+
<div className="space-y-1 leading-none">
129+
<FormLabel className="text-xs font-normal">
130+
I accept the{' '}
131+
<a
132+
href="https://www.harper.fast/resources/privacy-policy"
133+
target="_blank"
134+
rel="noreferrer"
135+
className="underline hover:text-blue-300"
136+
>
137+
Privacy Policy
138+
</a>{' '}
139+
and{' '}
140+
<a
141+
href="https://www.harper.fast/resources/paas-terms-of-service"
142+
target="_blank"
143+
rel="noreferrer"
144+
className="underline hover:text-blue-300"
145+
>
146+
Terms of Service
147+
</a>
148+
</FormLabel>
149+
<FormMessage />
150+
</div>
151+
</FormItem>
152+
)}
153+
/>
154+
);
155+
98156
return (
99157
<div className="text-white w-xs">
100158
<h2 className="text-2xl font-light">Sign up for Harper Fabric</h2>
101159

102-
<div className="flex flex-col gap-2 my-6">
103-
<GoogleAuthenticationButton text="Sign up with Google" />
104-
<GitHubAuthenticationButton text="Sign up with GitHub" />
105-
</div>
160+
<Form {...methods}>
161+
<div className="flex flex-col gap-2 my-6">
162+
{termsCheckbox}
163+
<GoogleAuthenticationButton
164+
text="Sign up with Google"
165+
disabled={!acceptTerms}
166+
onClick={onOAuthClick}
167+
/>
168+
<GitHubAuthenticationButton
169+
text="Sign up with GitHub"
170+
disabled={!acceptTerms}
171+
onClick={onOAuthClick}
172+
/>
173+
</div>
106174

107-
<hr className="border-gray-600" />
175+
<hr className="border-gray-600" />
108176

109-
<Form {...methods}>
110177
<form
111178
id="auth-signup-form"
112179
name="auth-signup-form"
@@ -206,45 +273,7 @@ export function SignUp() {
206273
</FormItem>
207274
)}
208275
/>
209-
<FormField
210-
control={control}
211-
name="acceptTerms"
212-
render={({ field }) => (
213-
<FormItem className="flex flex-row items-start space-x-3 space-y-0 p-1">
214-
<FormControl>
215-
<Input
216-
type="checkbox"
217-
className="size-4 rounded border-gray-300 bg-white text-purple-600 focus:ring-purple-500"
218-
checked={field.value}
219-
onChange={field.onChange}
220-
/>
221-
</FormControl>
222-
<div className="space-y-1 leading-none">
223-
<FormLabel className="text-xs font-normal">
224-
I accept the{' '}
225-
<a
226-
href="https://www.harper.fast/resources/privacy-policy"
227-
target="_blank"
228-
rel="noreferrer"
229-
className="underline hover:text-blue-300"
230-
>
231-
Privacy Policy
232-
</a>{' '}
233-
and{' '}
234-
<a
235-
href="https://www.harper.fast/resources/paas-terms-of-service"
236-
target="_blank"
237-
rel="noreferrer"
238-
className="underline hover:text-blue-300"
239-
>
240-
Terms of Service
241-
</a>
242-
</FormLabel>
243-
<FormMessage />
244-
</div>
245-
</FormItem>
246-
)}
247-
/>
276+
{termsCheckbox}
248277

249278
<Button type="submit" variant="submit" className="w-full rounded-full my-4">
250279
Sign Up For Free

src/features/auth/components/GitHubAuthenticationButton.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
import './GitHubAuthenticationButton.css';
2+
import { cx } from 'class-variance-authority';
23
import { GithubIcon } from 'lucide-react';
4+
import { MouseEventHandler } from 'react';
35

4-
export function GitHubAuthenticationButton({ text }: { text: 'Sign in with GitHub' | 'Sign up with GitHub' }) {
6+
export function GitHubAuthenticationButton({
7+
text,
8+
disabled,
9+
onClick,
10+
}: {
11+
text: 'Sign in with GitHub' | 'Sign up with GitHub';
12+
disabled?: boolean;
13+
onClick?: MouseEventHandler<HTMLAnchorElement>;
14+
}) {
515
return (
6-
<a href="/oauth/github/login?redirect=%2F%23%2Fcheck-oauth">
7-
<button className="github-signin-btn">
16+
<a href="/oauth/github/login?redirect=%2F%23%2Fcheck-oauth" onClick={onClick}>
17+
<button
18+
className={cx('github-signin-btn', disabled && 'opacity-50')}
19+
type="button"
20+
>
821
<GithubIcon className="github-icon" />
922
{text}
1023
</button>

src/features/auth/components/GoogleAuthenticationButton.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
import './GoogleAuthenticationButton.css';
2+
import { cx } from 'class-variance-authority';
3+
import { MouseEventHandler } from 'react';
24

3-
export function GoogleAuthenticationButton({ text }: { text: 'Sign in with Google' | 'Sign up with Google' }) {
5+
export function GoogleAuthenticationButton({
6+
text,
7+
disabled,
8+
onClick,
9+
}: {
10+
text: 'Sign in with Google' | 'Sign up with Google';
11+
disabled?: boolean;
12+
onClick?: MouseEventHandler<HTMLAnchorElement>;
13+
}) {
414
return (
5-
<a href="/oauth/google/login?redirect=%2F%23%2Fcheck-oauth">
6-
<button className="gsi-material-button">
15+
<a href="/oauth/google/login?redirect=%2F%23%2Fcheck-oauth" onClick={onClick}>
16+
<button
17+
className={cx('gsi-material-button', disabled && 'opacity-50')}
18+
type="button"
19+
>
720
<div className="gsi-material-button-state"></div>
821
<div className="gsi-material-button-content-wrapper">
922
<div className="gsi-material-button-icon">

0 commit comments

Comments
 (0)