Skip to content

Commit 404ffa8

Browse files
committed
chore: add captcha ui component
1 parent e679077 commit 404ffa8

File tree

14 files changed

+178
-27
lines changed

14 files changed

+178
-27
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ PUBLIC_ENV_NAME=###
33
SUPABASE_URL=https://PROJECT_ID.supabase.co
44
SUPABASE_PUBLIC_KEY=###
55

6+
CF_CAPTCHA_SITE_KEY=###
7+
CF_CAPTCHA_SECRET_KEY=###
8+
69
# Include in .env.test
710
E2E_USERNAME_ID=###
811
E2E_USERNAME=###

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,36 @@ Create so called "rules for AI" written in Markdown, used by tools such as GitHu
3737
```bash
3838
npm run build
3939
```
40+
## Local Supabase Setup
41+
42+
1. Install Supabase CLI
43+
44+
```bash
45+
brew install supabase
46+
```
47+
48+
2. Start Supabase (requires local Docker)
49+
50+
```bash
51+
supabase start
52+
```
53+
54+
3. Verify Supabase is running
55+
56+
```bash
57+
supabase status
58+
```
59+
60+
## Dotenv
61+
62+
Create `.env.local` file and add the following variables:
63+
64+
```bash
65+
PUBLIC_ENV_NAME=local
66+
SUPABASE_URL=http://localhost:54321
67+
SUPABASE_PUBLIC_KEY=your_supabase_anon_key
68+
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
69+
```
4070

4171
## Tech Stack
4272

astro.config.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export default defineConfig({
1616
SUPABASE_URL: envField.string({ context: 'server', access: 'secret' }),
1717
SUPABASE_PUBLIC_KEY: envField.string({ context: 'server', access: 'secret' }),
1818
SUPABASE_SERVICE_ROLE_KEY: envField.string({ context: 'server', access: 'secret' }),
19+
CF_CAPTCHA_SITE_KEY: envField.string({
20+
context: 'server',
21+
access: 'public',
22+
default: '1x00000000000000000000AA',
23+
}),
24+
CF_CAPTCHA_SECRET_KEY: envField.string({ context: 'server', access: 'secret' }),
1925
},
2026
},
2127
vite: {

package-lock.json

Lines changed: 38 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@tailwindcss/vite": "4.0.14",
3333
"@types/react-dom": "18.3.5",
3434
"astro": "^5.5.2",
35+
"axios": "1.9.0",
3536
"clsx": "^2.1.1",
3637
"fflate": "^0.8.2",
3738
"lucide-react": "0.479.0",

src/components/auth/LoginForm.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { loginSchema } from '../../types/auth';
77
import type { LoginFormData } from '../../types/auth';
88
import { useAuth } from '../../hooks/useAuth';
99

10-
export const LoginForm: React.FC = () => {
10+
interface LoginFormProps {
11+
cfCaptchaSiteKey: string;
12+
}
13+
14+
export const LoginForm: React.FC<LoginFormProps> = ({ cfCaptchaSiteKey }) => {
1115
const { login, error: apiError, isLoading } = useAuth();
1216
const {
1317
register,
@@ -55,6 +59,10 @@ export const LoginForm: React.FC = () => {
5559
{...register('password')}
5660
/>
5761

62+
<div className="flex flex-row justify-center">
63+
<div className="cf-turnstile" data-sitekey={cfCaptchaSiteKey} data-size="normal"></div>
64+
</div>
65+
5866
<div className="flex items-center justify-between">
5967
<div className="text-sm">
6068
<a

src/components/auth/ResetPasswordForm.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { resetPasswordSchema } from '../../types/auth';
77
import type { ResetPasswordFormData } from '../../types/auth';
88
import { useAuth } from '../../hooks/useAuth';
99

10-
export const ResetPasswordForm: React.FC = () => {
10+
interface ResetPasswordFormProps {
11+
cfCaptchaSiteKey: string;
12+
}
13+
14+
export const ResetPasswordForm: React.FC<ResetPasswordFormProps> = ({ cfCaptchaSiteKey }) => {
1115
const { resetPassword, error: apiError, isLoading } = useAuth();
1216
const [error, setError] = useState<string | null>(null);
1317
const {
@@ -78,6 +82,10 @@ export const ResetPasswordForm: React.FC = () => {
7882
{...register('email')}
7983
/>
8084

85+
<div className="flex flex-row justify-center">
86+
<div className="cf-turnstile" data-sitekey={cfCaptchaSiteKey} data-size="normal"></div>
87+
</div>
88+
8189
<button
8290
type="submit"
8391
disabled={isLoading}

src/components/auth/SignupForm.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { signupSchema } from '../../types/auth';
77
import type { SignupFormData } from '../../types/auth';
88
import { useAuth } from '../../hooks/useAuth';
99

10-
export const SignupForm: React.FC = () => {
10+
interface SignupFormProps {
11+
cfCaptchaSiteKey: string;
12+
}
13+
14+
export const SignupForm: React.FC<SignupFormProps> = ({ cfCaptchaSiteKey }) => {
1115
const { signup, error: apiError, isLoading } = useAuth();
1216
const {
1317
register,
@@ -83,6 +87,10 @@ export const SignupForm: React.FC = () => {
8387
{...register('confirmPassword')}
8488
/>
8589

90+
<div className="flex flex-row justify-center">
91+
<div className="cf-turnstile" data-sitekey={cfCaptchaSiteKey} data-size="normal"></div>
92+
</div>
93+
8694
<div className="space-y-2">
8795
<div className="flex items-start">
8896
<div className="flex items-center h-5">

src/env.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ interface ImportMetaEnv {
2121
readonly SUPABASE_URL: string;
2222
readonly SUPABASE_PUBLIC_KEY: string;
2323
readonly SUPABASE_SERVICE_ROLE_KEY: string;
24+
readonly CF_CAPTCHA_SITE_KEY: string;
25+
readonly CF_CAPTCHA_SECRET_KEY: string;
2426
}
2527

2628
interface ImportMeta {

src/pages/auth/login.astro

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import LoginForm from '../../components/auth/LoginForm';
55
import { createSupabaseServerInstance } from '../../db/supabase.client';
66
import { isFeatureEnabled } from '../../features/featureFlags';
77
8+
import { CF_CAPTCHA_SITE_KEY } from 'astro:env/server';
9+
810
// Check if auth feature is enabled
911
if (!isFeatureEnabled('auth')) {
1012
return Astro.redirect('/');
@@ -30,8 +32,9 @@ if (user) {
3032
<div class="flex flex-col h-screen max-h-screen bg-gray-950">
3133
<main class="flex-grow">
3234
<AuthLayout title="Welcome back" subtitle="Sign in to your account to continue">
33-
<LoginForm client:only="react" />
35+
<LoginForm client:only="react" cfCaptchaSiteKey={CF_CAPTCHA_SITE_KEY} />
3436
</AuthLayout>
3537
</main>
3638
</div>
39+
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer></script>
3740
</Layout>

0 commit comments

Comments
 (0)