Terminal
This commit is contained in:
@@ -1,99 +0,0 @@
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||||
import { toast } from "sonner";
|
||||
import { GraduationCap } from "lucide-react";
|
||||
|
||||
const searchSchema = z.object({ mode: z.enum(["signin", "signup"]).optional() });
|
||||
|
||||
export const Route = createFileRoute("/auth")({
|
||||
validateSearch: searchSchema,
|
||||
head: () => ({ meta: [{ title: "Sign in — Bayside Academy" }] }),
|
||||
component: AuthPage,
|
||||
});
|
||||
|
||||
function AuthPage() {
|
||||
const navigate = useNavigate();
|
||||
const { mode } = Route.useSearch();
|
||||
const [tab, setTab] = useState<"signin" | "signup">(mode ?? "signin");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [fullName, setFullName] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const onSignIn = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const { error } = await supabase.auth.signInWithPassword({ email, password });
|
||||
setLoading(false);
|
||||
if (error) return toast.error(error.message);
|
||||
navigate({ to: "/dashboard" });
|
||||
};
|
||||
|
||||
const onSignUp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: { emailRedirectTo: window.location.origin, data: { full_name: fullName } },
|
||||
});
|
||||
setLoading(false);
|
||||
if (error) return toast.error(error.message);
|
||||
toast.success("Account created. You can sign in now.");
|
||||
setTab("signin");
|
||||
};
|
||||
|
||||
const onGoogle = async () => {
|
||||
// Native Supabase OAuth: redirects the browser to Google, then back to
|
||||
// redirectTo. supabase-js (detectSessionInUrl) restores the session on
|
||||
// return, and useAuth's onAuthStateChange picks it up.
|
||||
const { error } = await supabase.auth.signInWithOAuth({
|
||||
provider: "google",
|
||||
options: { redirectTo: `${window.location.origin}/dashboard` },
|
||||
});
|
||||
if (error) toast.error(error.message ?? "Google sign-in failed");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-muted/30 p-4">
|
||||
<div className="w-full max-w-md bg-card border rounded-lg p-8 shadow-sm">
|
||||
<div className="flex justify-center mb-6">
|
||||
<img src="/bayside-logo.png" alt="Bayside Academy" className="h-12 w-auto" />
|
||||
</div>
|
||||
<Tabs value={tab} onValueChange={(v) => setTab(v as "signin" | "signup")}>
|
||||
<TabsList className="grid grid-cols-2 w-full">
|
||||
<TabsTrigger value="signin">Sign in</TabsTrigger>
|
||||
<TabsTrigger value="signup">Create account</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="signin">
|
||||
<form onSubmit={onSignIn} className="space-y-4 mt-4">
|
||||
<div><Label>Email</Label><Input type="email" required value={email} onChange={(e) => setEmail(e.target.value)} /></div>
|
||||
<div><Label>Password</Label><Input type="password" required value={password} onChange={(e) => setPassword(e.target.value)} /></div>
|
||||
<Button type="submit" className="w-full" disabled={loading}>Sign in</Button>
|
||||
</form>
|
||||
</TabsContent>
|
||||
<TabsContent value="signup">
|
||||
<form onSubmit={onSignUp} className="space-y-4 mt-4">
|
||||
<div><Label>Full name</Label><Input required value={fullName} onChange={(e) => setFullName(e.target.value)} /></div>
|
||||
<div><Label>Email</Label><Input type="email" required value={email} onChange={(e) => setEmail(e.target.value)} /></div>
|
||||
<div><Label>Password</Label><Input type="password" required minLength={6} value={password} onChange={(e) => setPassword(e.target.value)} /></div>
|
||||
<Button type="submit" className="w-full" disabled={loading}>Create account</Button>
|
||||
<p className="text-xs text-muted-foreground">The first account becomes admin. Other accounts default to parent — an admin can change your role.</p>
|
||||
</form>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<div className="my-4 flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<div className="flex-1 border-t" /> OR <div className="flex-1 border-t" />
|
||||
</div>
|
||||
<Button variant="outline" className="w-full" onClick={onGoogle}>Continue with Google</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user