Compare commits

...

1 Commits

Author SHA1 Message Date
Nicholas Tindle
ae20da8aaa fix(frontend): improve waitlist error display for users not on allowlist
- Updated EmailNotAllowedModal with clear waitlist CTA and helpful messaging
- Added "Join Waitlist" button that opens https://agpt.co/waitlist
- Fixed OAuth provider signup/login to properly display waitlist modal
- Enhanced auth-code-error page to detect and display waitlist errors
- Added helpful guidance about checking email and Discord support link
- Consistent waitlist error handling across all auth flows

Fixes OPEN-2794

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 12:37:03 -05:00
4 changed files with 147 additions and 16 deletions

View File

@@ -2,11 +2,16 @@
import { isServerSide } from "@/lib/utils/is-server-side"; import { isServerSide } from "@/lib/utils/is-server-side";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Button } from "@/components/atoms/Button/Button";
import { Text } from "@/components/atoms/Text/Text";
import { Card } from "@/components/atoms/Card/Card";
import { useRouter } from "next/navigation";
export default function AuthErrorPage() { export default function AuthErrorPage() {
const [errorType, setErrorType] = useState<string | null>(null); const [errorType, setErrorType] = useState<string | null>(null);
const [errorCode, setErrorCode] = useState<string | null>(null); const [errorCode, setErrorCode] = useState<string | null>(null);
const [errorDescription, setErrorDescription] = useState<string | null>(null); const [errorDescription, setErrorDescription] = useState<string | null>(null);
const router = useRouter();
useEffect(() => { useEffect(() => {
// This code only runs on the client side // This code only runs on the client side
@@ -23,15 +28,105 @@ export default function AuthErrorPage() {
}, []); }, []);
if (!errorType && !errorCode && !errorDescription) { if (!errorType && !errorCode && !errorDescription) {
return <div>Loading...</div>; return (
<div className="flex h-screen items-center justify-center">
<Text variant="body">Loading...</Text>
</div>
);
} }
// Check if this is a waitlist/not allowed error
const isWaitlistError =
errorCode === "403" ||
errorDescription?.toLowerCase().includes("not allowed") ||
errorDescription?.toLowerCase().includes("waitlist") ||
errorDescription?.toLowerCase().includes("allowlist");
if (isWaitlistError) {
return (
<div className="flex h-screen items-center justify-center">
<Card className="w-full max-w-md p-8">
<div className="flex flex-col items-center gap-6">
<Text variant="h3">Join the Waitlist</Text>
<div className="flex flex-col gap-4 text-center">
<Text variant="body">
AutoGPT Platform is currently in closed beta. Your email address
isn&apos;t on our current allowlist for early access.
</Text>
<Text variant="small" className="text-muted-foreground">
Join our waitlist to get notified when we open up access!
</Text>
</div>
<div className="flex gap-3">
<Button
variant="secondary"
onClick={() => {
window.open("https://agpt.co/waitlist", "_blank");
}}
>
Join Waitlist
</Button>
<Button variant="primary" onClick={() => router.push("/login")}>
Back to Login
</Button>
</div>
<div className="flex flex-col gap-2">
<Text
variant="small"
className="text-center text-muted-foreground"
>
Already signed up for the waitlist? Make sure you&apos;re using
the exact same email address you used when signing up.
</Text>
<Text
variant="small"
className="text-center text-muted-foreground"
>
If you&apos;re not sure which email you used or need help,{" "}
<a
href="https://discord.gg/autogpt"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-foreground"
>
reach out on Discord
</a>
</Text>
</div>
</div>
</Card>
</div>
);
}
// Default error display for other types of errors
return ( return (
<div> <div className="flex h-screen items-center justify-center">
<h1>Authentication Error</h1> <Card className="w-full max-w-md p-8">
{errorType && <p>Error Type: {errorType}</p>} <div className="flex flex-col items-center gap-6">
{errorCode && <p>Error Code: {errorCode}</p>} <Text variant="h3">Authentication Error</Text>
{errorDescription && <p>Error Description: {errorDescription}</p>} <div className="flex flex-col gap-2 text-center">
{errorType && (
<Text variant="body">
<strong>Error Type:</strong> {errorType}
</Text>
)}
{errorCode && (
<Text variant="body">
<strong>Error Code:</strong> {errorCode}
</Text>
)}
{errorDescription && (
<Text variant="body">
<strong>Description:</strong> {errorDescription}
</Text>
)}
</div>
<Button variant="primary" onClick={() => router.push("/login")}>
Back to Login
</Button>
</div>
</Card>
</div> </div>
); );
} }

View File

@@ -67,7 +67,7 @@ export function useLoginPage() {
if (!response.ok) { if (!response.ok) {
const { error } = await response.json(); const { error } = await response.json();
if (typeof error === "string" && error.includes("not_allowed")) { if (error === "not_allowed") {
setShowNotAllowedModal(true); setShowNotAllowedModal(true);
} else { } else {
setFeedback(error || "Failed to start OAuth flow"); setFeedback(error || "Failed to start OAuth flow");

View File

@@ -70,6 +70,13 @@ export function useSignupPage() {
const { error } = await response.json(); const { error } = await response.json();
setIsGoogleLoading(false); setIsGoogleLoading(false);
resetCaptcha(); resetCaptcha();
// Check for waitlist error
if (error === "not_allowed") {
setShowNotAllowedModal(true);
return;
}
toast({ toast({
title: error || "Failed to start OAuth flow", title: error || "Failed to start OAuth flow",
variant: "destructive", variant: "destructive",

View File

@@ -15,16 +15,45 @@ export function EmailNotAllowedModal({ isOpen, onClose }: Props) {
> >
<Dialog.Content> <Dialog.Content>
<div className="flex flex-col items-center gap-8 py-4"> <div className="flex flex-col items-center gap-8 py-4">
<Text variant="h3">Access Restricted</Text> <Text variant="h3">Join the Waitlist</Text>
<Text variant="large-medium" className="text-center"> <div className="flex flex-col gap-4">
We&apos;re currently in a limited access phase. Your email address <Text variant="large-medium" className="text-center">
isn&apos;t on our current allowlist for early access. If you believe AutoGPT Platform is currently in closed beta. Your email address
this is an error or would like to request access, please contact us. isn&apos;t on our current allowlist for early access.
</Text> </Text>
<div className="flex justify-end pt-4"> <Text variant="body" className="text-center">
<Button variant="primary" onClick={onClose}> Join our waitlist to get notified when we open up access!
I understand </Text>
</div>
<div className="flex gap-3">
<Button
variant="secondary"
onClick={() => {
window.open("https://agpt.co/waitlist", "_blank");
}}
>
Join Waitlist
</Button> </Button>
<Button variant="primary" onClick={onClose}>
Close
</Button>
</div>
<div className="flex flex-col gap-2">
<Text variant="small" className="text-center text-muted-foreground">
Already signed up for the waitlist? Make sure you&apos;re using
the exact same email address you used when signing up.
</Text>
<Text variant="small" className="text-center text-muted-foreground">
If you&apos;re not sure which email you used or need help,{" "}
<a
href="https://discord.gg/autogpt"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-foreground"
>
reach out on Discord
</a>
</Text>
</div> </div>
</div> </div>
</Dialog.Content> </Dialog.Content>