Skip to content
Open
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
22 changes: 22 additions & 0 deletions components/organisms/waitlist-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export function WaitlistModal() {
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
const [errorMessage, setErrorMessage] = useState("");
const [csrfToken, setCsrfToken] = useState<string | null>(null);
const [ariaMessage, setAriaMessage] = useState("");

// Fetch CSRF token when modal opens
useEffect(() => {
Expand All @@ -60,9 +61,21 @@ export function WaitlistModal() {
},
});

// Handle validation errors for screen readers
useEffect(() => {
if (Object.keys(errors).length > 0) {
// Find the first error message to announce
const firstError = Object.values(errors)[0];
if (firstError?.message) {
setAriaMessage(firstError.message as string);
}
}
}, [errors]);

const onSubmit = async (values: WaitlistFormValues) => {
setStatus("loading");
setErrorMessage("");
setAriaMessage("");

try {
// Local API call that handles CSRF and forwarding/demo mode
Expand All @@ -85,6 +98,7 @@ export function WaitlistModal() {
setStatus("error");
const message = error instanceof Error ? error.message : "An unexpected error occurred";
setErrorMessage(message);
setAriaMessage(message);
toast({
variant: "destructive",
title: "Something went wrong",
Expand All @@ -95,6 +109,7 @@ export function WaitlistModal() {

const handleSuccess = () => {
setStatus("success");
setAriaMessage("Successfully joined the waitlist");
toast({
title: "You're on the list!",
description: "Keep an eye on your inbox. We'll be in touch soon.",
Expand All @@ -103,6 +118,7 @@ export function WaitlistModal() {
setTimeout(() => {
reset();
setStatus("idle");
setAriaMessage("");
closeWaitlist();
}, 2500);
};
Expand All @@ -114,13 +130,19 @@ export function WaitlistModal() {
setTimeout(() => {
reset();
setStatus("idle");
setAriaMessage("");
}, 300);
}
};

return (
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
<DialogContent className="sm:max-w-md glass-card gradient-border overflow-hidden">
{/* Screen reader only live region for status updates */}
<div className="sr-only" aria-live="polite" role="status">
{ariaMessage}
</div>

{/* Decorative background glow */}
<div className="absolute -top-24 -right-24 w-48 h-48 bg-primary/20 rounded-full blur-[48px] pointer-events-none" />
<div className="absolute -bottom-24 -left-24 w-48 h-48 bg-primary/20 rounded-full blur-[48px] pointer-events-none" />
Expand Down