279 lines
12 KiB
TypeScript
279 lines
12 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useAuth, registrationSchema, RegistrationData } from "@/hooks/use-auth";
|
|
import { useLocation } from "wouter";
|
|
import { loginSchema, Login } from "@shared/schema";
|
|
import {
|
|
Form,
|
|
FormControl,
|
|
FormField,
|
|
FormItem,
|
|
FormLabel,
|
|
FormMessage
|
|
} from "@/components/ui/form";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { Loader2 } from "lucide-react";
|
|
|
|
export default function AuthPage() {
|
|
const { user, loginMutation, registerMutation } = useAuth();
|
|
const [_, navigate] = useLocation();
|
|
const [activeTab, setActiveTab] = useState<"login" | "register">("login");
|
|
|
|
// Redirect if user is already logged in
|
|
useEffect(() => {
|
|
if (user) {
|
|
navigate("/");
|
|
}
|
|
}, [user, navigate]);
|
|
|
|
// Set meta data for SEO
|
|
useEffect(() => {
|
|
document.title = "Login or Sign Up | Pilates with Fadia";
|
|
const metaDescription = document.querySelector('meta[name="description"]');
|
|
if (metaDescription) {
|
|
metaDescription.setAttribute("content", "Create an account or login to book classes, access community features, and more with Pilates with Fadia.");
|
|
}
|
|
}, []);
|
|
|
|
// Login form
|
|
const loginForm = useForm<Login>({
|
|
resolver: zodResolver(loginSchema),
|
|
defaultValues: {
|
|
username: "",
|
|
password: "",
|
|
},
|
|
});
|
|
|
|
// Registration form
|
|
const registerForm = useForm<RegistrationData>({
|
|
resolver: zodResolver(registrationSchema),
|
|
defaultValues: {
|
|
username: "",
|
|
email: "",
|
|
fullName: "",
|
|
password: "",
|
|
confirmPassword: "",
|
|
},
|
|
});
|
|
|
|
const onLoginSubmit = (data: Login) => {
|
|
loginMutation.mutate(data);
|
|
};
|
|
|
|
const onRegisterSubmit = (data: RegistrationData) => {
|
|
// Remove confirmPassword before sending to API
|
|
const { confirmPassword, ...registerData } = data;
|
|
registerMutation.mutate(registerData);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 py-16">
|
|
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex flex-col md:flex-row gap-8 max-w-7xl mx-auto">
|
|
{/* Left column with auth forms */}
|
|
<div className="md:w-1/2">
|
|
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as "login" | "register")} className="w-full">
|
|
<TabsList className="grid w-full grid-cols-2 mb-8">
|
|
<TabsTrigger value="login">Login</TabsTrigger>
|
|
<TabsTrigger value="register">Sign Up</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="login">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Welcome Back</CardTitle>
|
|
<CardDescription>Login to access your account</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Form {...loginForm}>
|
|
<form onSubmit={loginForm.handleSubmit(onLoginSubmit)} className="space-y-6">
|
|
<FormField
|
|
control={loginForm.control}
|
|
name="username"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Username</FormLabel>
|
|
<FormControl>
|
|
<Input placeholder="Enter your username" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={loginForm.control}
|
|
name="password"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Password</FormLabel>
|
|
<FormControl>
|
|
<Input type="password" placeholder="Enter your password" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox id="remember-me" />
|
|
<label htmlFor="remember-me" className="text-sm text-gray-600">Remember me</label>
|
|
</div>
|
|
<a href="#" className="text-sm text-teal hover:underline">Forgot password?</a>
|
|
</div>
|
|
<Button
|
|
type="submit"
|
|
className="w-full bg-teal text-white"
|
|
disabled={loginMutation.isPending}
|
|
>
|
|
{loginMutation.isPending ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
Logging in...
|
|
</>
|
|
) : (
|
|
"Login"
|
|
)}
|
|
</Button>
|
|
</form>
|
|
</Form>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="register">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Create an Account</CardTitle>
|
|
<CardDescription>Sign up to book classes and access exclusive content</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Form {...registerForm}>
|
|
<form onSubmit={registerForm.handleSubmit(onRegisterSubmit)} className="space-y-6">
|
|
<FormField
|
|
control={registerForm.control}
|
|
name="username"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Username</FormLabel>
|
|
<FormControl>
|
|
<Input placeholder="Choose a username" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={registerForm.control}
|
|
name="email"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Email</FormLabel>
|
|
<FormControl>
|
|
<Input type="email" placeholder="Enter your email" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={registerForm.control}
|
|
name="fullName"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Full Name</FormLabel>
|
|
<FormControl>
|
|
<Input placeholder="Enter your full name" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={registerForm.control}
|
|
name="password"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Password</FormLabel>
|
|
<FormControl>
|
|
<Input type="password" placeholder="Create a password" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={registerForm.control}
|
|
name="confirmPassword"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Confirm Password</FormLabel>
|
|
<FormControl>
|
|
<Input type="password" placeholder="Confirm your password" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<Button
|
|
type="submit"
|
|
className="w-full bg-purple text-white"
|
|
disabled={registerMutation.isPending}
|
|
>
|
|
{registerMutation.isPending ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
Creating account...
|
|
</>
|
|
) : (
|
|
"Sign Up"
|
|
)}
|
|
</Button>
|
|
</form>
|
|
</Form>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
|
|
{/* Right column with hero section */}
|
|
<div className="md:w-1/2 bg-teal rounded-lg p-8 text-white flex flex-col justify-center">
|
|
<h2 className="text-3xl md:text-4xl font-playfair font-bold mb-6">Begin Your Pilates Journey</h2>
|
|
<p className="text-teal-50 mb-6">
|
|
Join our community of wellness enthusiasts and transform your body and mind through the art of Pilates. Create an account to access:
|
|
</p>
|
|
<ul className="space-y-3 mb-8">
|
|
<li className="flex items-center">
|
|
<i className="fas fa-check-circle mr-2"></i>
|
|
<span>Convenient class booking and scheduling</span>
|
|
</li>
|
|
<li className="flex items-center">
|
|
<i className="fas fa-check-circle mr-2"></i>
|
|
<span>Community resources and support</span>
|
|
</li>
|
|
<li className="flex items-center">
|
|
<i className="fas fa-check-circle mr-2"></i>
|
|
<span>Special member-only workshops</span>
|
|
</li>
|
|
<li className="flex items-center">
|
|
<i className="fas fa-check-circle mr-2"></i>
|
|
<span>Personalized fitness tracking</span>
|
|
</li>
|
|
</ul>
|
|
<div>
|
|
<p className="italic text-sm text-teal-100 border-l-4 border-white pl-4 py-2 font-aref text-lg">
|
|
"The mind, when housed within a healthful body, possesses a glorious sense of power."
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|