DistractIQ / src /pages /Auth.tsx
github-actions
Initial clean deploy
7ff860b
Raw
History Blame Contribute Delete
5.47 kB
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/contexts/AuthContext";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";
import { Brain, Sparkles } from "lucide-react";
const LAST_NAME_KEY = "distractiq.lastUsername";
const NAME_REGEX = /^[a-zA-Z0-9_]{3,24}$/;
// Deterministic synthetic credentials so a username always maps to the same account.
const toEmail = (name: string) => `${name.toLowerCase()}@distractiq.local`;
// Note: not security-grade — by design, no password to remember.
const toPassword = (name: string) => `diq_${name.toLowerCase()}_focus_2025`;
export default function Auth() {
const navigate = useNavigate();
const { user, loading } = useAuth();
const [busy, setBusy] = useState(false);
const [username, setUsername] = useState("");
const [remembered, setRemembered] = useState<string | null>(null);
useEffect(() => {
document.title = "Welcome · DistractIQ";
const saved = localStorage.getItem(LAST_NAME_KEY);
if (saved) {
setUsername(saved);
setRemembered(saved);
}
}, []);
useEffect(() => {
if (!loading && user) navigate("/", { replace: true });
}, [user, loading, navigate]);
const enter = async (e: React.FormEvent) => {
e.preventDefault();
const name = username.trim();
if (!NAME_REGEX.test(name)) {
toast.error("Use 3–24 letters, numbers, or underscores.");
return;
}
setBusy(true);
const email = toEmail(name);
const password = toPassword(name);
// Try sign-in first (returning user)
const { error: signInErr } = await supabase.auth.signInWithPassword({ email, password });
if (signInErr) {
// Likely first-time — create account
const { error: signUpErr } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${window.location.origin}/`,
data: { username: name },
},
});
if (signUpErr) {
setBusy(false);
toast.error(signUpErr.message);
return;
}
// After sign-up, session is created automatically (auto-confirm on)
toast.success(`Welcome, ${name}! ✨`);
} else {
toast.success(`Welcome back, ${name} 👋`);
}
localStorage.setItem(LAST_NAME_KEY, name);
setBusy(false);
navigate("/", { replace: true });
};
const useDifferent = () => {
setUsername("");
setRemembered(null);
};
return (
<main className="min-h-screen flex items-center justify-center p-6">
<div className="w-full max-w-md glass-strong rounded-3xl p-8 animate-fade-in">
<div className="flex items-center justify-center gap-2 mb-2">
<div className="relative">
<Brain className="h-9 w-9 text-primary" />
<div className="absolute inset-0 blur-xl bg-primary/40" />
</div>
<h1 className="text-3xl font-display font-bold">
Distract<span className="text-gradient-emerald">IQ</span>
</h1>
</div>
<p className="text-center text-muted-foreground text-sm mb-8">
Quantify your focus. Beat your distractions.
</p>
{remembered && (
<div className="mb-5 rounded-2xl bg-primary/10 border border-primary/30 px-4 py-3 text-sm flex items-center gap-2 animate-fade-in">
<Sparkles className="h-4 w-4 text-primary shrink-0" />
<span>
Welcome back, <span className="font-semibold text-primary">{remembered}</span>. Tap continue to jump in.
</span>
</div>
)}
<form onSubmit={enter} className="space-y-4">
<div>
<Label htmlFor="name" className="text-xs uppercase tracking-widest text-muted-foreground">
Your name
</Label>
<Input
id="name"
autoFocus
required
minLength={3}
maxLength={24}
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="focus_ninja"
className="mt-1.5 h-12 text-lg font-display"
/>
<p className="text-[11px] text-muted-foreground mt-1.5">
3–24 characters · letters, numbers, underscores. Same name later = same account.
</p>
</div>
<Button
type="submit"
disabled={busy}
className="w-full h-12 bg-gradient-emerald text-primary-foreground font-semibold text-base"
>
{busy ? "Entering..." : remembered ? `Continue as ${remembered || username}` : "Enter DistractIQ →"}
</Button>
{remembered && (
<button
type="button"
onClick={useDifferent}
className="w-full text-xs text-muted-foreground hover:text-foreground transition"
>
Use a different name
</button>
)}
</form>
<p className="mt-6 text-[10px] text-center text-muted-foreground/70 leading-relaxed">
No password, no email — your name is your key. Pick something unique to you so no one else claims it.
</p>
</div>
</main>
);
}