From c36b7c81df048cf3f4f190981c302d02612302fd Mon Sep 17 00:00:00 2001 From: Jared Schoeny Date: Sat, 13 Dec 2025 15:39:22 -1000 Subject: [PATCH] Remove invite code requirement for signup --- src/app/signup/actions.ts | 89 ++++-------------------------- src/components/Auth/SignupForm.tsx | 31 +---------- 2 files changed, 13 insertions(+), 107 deletions(-) diff --git a/src/app/signup/actions.ts b/src/app/signup/actions.ts index 7a33677..dc80321 100644 --- a/src/app/signup/actions.ts +++ b/src/app/signup/actions.ts @@ -3,9 +3,8 @@ import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation' import { AuthError } from '@supabase/supabase-js' -import { get } from '@vercel/edge-config' -import { createClient, createServiceClient } from '@/utils/supabase/server' +import { createClient } from '@/utils/supabase/server' import { validateEmail, validatePassword } from '@/utils/auth' import { sendDiscordMessageEmbed } from '@/utils/discord' @@ -34,13 +33,11 @@ export interface AuthActionState { export async function signup(state: AuthActionState, payload: FormData) { const supabase = await createClient() - const service = await createServiceClient() const data = { email: payload.get('email') as string, password: payload.get('password') as string, } - const inviteCode = (payload.get('inviteCode') as string | null)?.trim() || '' const { error: emailError } = validateEmail(data.email); if (emailError) { @@ -52,33 +49,6 @@ export async function signup(state: AuthActionState, payload: FormData) { return { error: passwordError }; } - if (!inviteCode) { - return { error: 'An invite code is required to sign up.' } - } - - // Allow static invite codes via Edge Config to bypass DB checks - let isStaticInvite = false - try { - const staticCodes = (await get('staticInviteCodes')) || [] - if (Array.isArray(staticCodes)) { - isStaticInvite = staticCodes.includes(inviteCode) - } - } catch {} - - if (!isStaticInvite) { - // Pre-check: ensure invite exists and is unused before attempting signup - const { data: availableInvite, error: inviteCheckError } = await service - .from('invite_codes') - .select('code') - .eq('code', inviteCode) - .is('used_by', null) - .maybeSingle() - - if (inviteCheckError || !availableInvite) { - return { error: 'Invalid or already used invite code.' } - } - } - const { data: signUpResult, error } = await supabase.auth.signUp(data) if (error) { @@ -86,52 +56,17 @@ export async function signup(state: AuthActionState, payload: FormData) { } const userId = signUpResult.user?.id || null - if (isStaticInvite) { - console.log('[signup] Static invite code used:', { inviteCode, userId }) - if (process.env.DISCORD_WEBHOOK_ADMIN_URL) { - await sendDiscordMessageEmbed(process.env.DISCORD_WEBHOOK_ADMIN_URL, [ - { - title: 'New User Signup', - description: `A new user (\`${userId}\`) has signed up using the static invite code: \`${inviteCode}\``, - color: 0x40f56a, - footer: { - text: 'A notification will be sent when this user has created their profile' - } - }, - ]); - } - } else { - // Finalize: set used_by to the new user id iff still unused (atomic) - const { data: finalized, error: finalizeError } = await service - .from('invite_codes') - .update({ used_by: userId ?? null }) - .eq('code', inviteCode) - .is('used_by', null) - .select('code') - .maybeSingle() - - if (finalizeError || !finalized) { - // The code claim could not be finalized (race). Roll back user creation. - if (userId) { - try { - await service.auth.admin.deleteUser(userId) - } catch {} - } - return { error: 'Invite code is no longer available. Please try again.' } - } else { - if (process.env.DISCORD_WEBHOOK_ADMIN_URL) { - await sendDiscordMessageEmbed(process.env.DISCORD_WEBHOOK_ADMIN_URL, [ - { - title: 'New User Signup', - description: `A new user (\`${userId}\`) has signed up using the invite code: \`${inviteCode}\``, - color: 0x40f56a, - footer: { - text: 'A notification will be sent when this user has created their profile' - } - }, - ]); - } - } + if (process.env.DISCORD_WEBHOOK_ADMIN_URL) { + await sendDiscordMessageEmbed(process.env.DISCORD_WEBHOOK_ADMIN_URL, [ + { + title: 'New User Signup', + description: `A new user (\`${userId}\`) has signed up.`, + color: 0x40f56a, + footer: { + text: 'A notification will be sent when this user has created their profile' + } + }, + ]); } revalidatePath('/', 'layout'); diff --git a/src/components/Auth/SignupForm.tsx b/src/components/Auth/SignupForm.tsx index 81c6da6..2053a2d 100644 --- a/src/components/Auth/SignupForm.tsx +++ b/src/components/Auth/SignupForm.tsx @@ -14,14 +14,13 @@ export default function SignupForm() { const [email, setEmail] = React.useState(""); const [password, setPassword] = React.useState(""); const [confirm, setConfirm] = React.useState(""); - const [invite, setInvite] = React.useState(""); const [showPassword, setShowPassword] = React.useState(false); const [emailError, setEmailError] = React.useState(null); const [passwordError, setPasswordError] = React.useState(null); const [state, formAction, isPending] = useActionState(signup, { error: null }); const passwordsMatch = password === confirm; - const isValid = !emailError && !passwordError && passwordsMatch && Boolean(invite); + const isValid = !emailError && !passwordError && passwordsMatch; useEffect(() => { const { error } = validateEmail(email); @@ -35,13 +34,6 @@ export default function SignupForm() { const redirectTo = searchParams.get("redirectTo"); - useEffect(() => { - const inviteFromParams = searchParams.get("invite") || ""; - if (inviteFromParams) { - setInvite(inviteFromParams); - } - }, []); - // Redirect if user already authenticated (e.g., opened signup while logged in) useEffect(() => { if (!user) return; @@ -60,27 +52,6 @@ export default function SignupForm() { {state?.error} )} -
- - setInvite(e.target.value)} - placeholder="Enter your invite code" - className={`h-11 rounded-md bg-[var(--surface-2)] px-3 text-sm ring-1 ring-inset ring-[var(--border)] focus:outline-none focus:ring-2 focus:ring-[var(--ring)] ${ - invite ? "bg-[var(--surface-2)] ring-[var(--border)]" : "bg-[var(--surface-2)] ring-[var(--border)]" - }`} - required - inputMode="text" - autoComplete="off" - spellCheck={false} - /> - {!invite && ( - An invite code is required to create an account. - )} -