feat/book-now #6
@ -495,10 +495,10 @@ export default function BookNowPage() {
|
||||
}
|
||||
required
|
||||
>
|
||||
<SelectTrigger id="appointmentType" className="h-11">
|
||||
<SelectTrigger id="appointmentType" className="h-11 bg-white">
|
||||
<SelectValue placeholder="Select appointment type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectContent className="bg-white">
|
||||
<SelectItem value="initial-consultation">
|
||||
Initial Consultation
|
||||
</SelectItem>
|
||||
@ -555,7 +555,7 @@ export default function BookNowPage() {
|
||||
<SelectTrigger id="preferredTime" className="h-11">
|
||||
<SelectValue placeholder="Select time" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectContent className="bg-white">
|
||||
<SelectItem value="9:00 AM">9:00 AM</SelectItem>
|
||||
<SelectItem value="10:00 AM">10:00 AM</SelectItem>
|
||||
<SelectItem value="11:00 AM">11:00 AM</SelectItem>
|
||||
|
||||
@ -11,7 +11,6 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Eye, EyeOff, Loader2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
interface LoginDialogProps {
|
||||
open: boolean;
|
||||
@ -19,14 +18,22 @@ interface LoginDialogProps {
|
||||
onLoginSuccess: () => void;
|
||||
}
|
||||
|
||||
// Login Dialog component
|
||||
export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogProps) {
|
||||
const [isSignup, setIsSignup] = useState(false);
|
||||
const [loginData, setLoginData] = useState({
|
||||
email: "",
|
||||
password: "",
|
||||
});
|
||||
const [signupData, setSignupData] = useState({
|
||||
fullName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
});
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [rememberMe, setRememberMe] = useState(false);
|
||||
const [loginLoading, setLoginLoading] = useState(false);
|
||||
const [signupLoading, setSignupLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
@ -49,20 +56,139 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
|
||||
}
|
||||
};
|
||||
|
||||
const handleSignup = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSignupLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// Simulate signup API call
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
// After successful signup, automatically log in and proceed
|
||||
setSignupLoading(false);
|
||||
onOpenChange(false);
|
||||
onLoginSuccess();
|
||||
} catch (err) {
|
||||
setError("Signup failed. Please try again.");
|
||||
setSignupLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSwitchToSignup = () => {
|
||||
setIsSignup(true);
|
||||
setError(null);
|
||||
setLoginData({ email: "", password: "" });
|
||||
};
|
||||
|
||||
const handleSwitchToLogin = () => {
|
||||
setIsSignup(false);
|
||||
setError(null);
|
||||
setSignupData({ fullName: "", email: "", phone: "" });
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-md bg-white">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-3xl font-bold bg-linear-to-r from-rose-600 via-pink-600 to-rose-600 bg-clip-text text-transparent">
|
||||
Welcome back
|
||||
{isSignup ? "Create an account" : "Welcome back"}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-gray-600">
|
||||
Please log in to complete your booking
|
||||
{isSignup
|
||||
? "Sign up to complete your booking"
|
||||
: "Please log in to complete your booking"}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{/* Login Form */}
|
||||
<form className="space-y-6 mt-4" onSubmit={handleLogin}>
|
||||
{/* Signup Form */}
|
||||
{isSignup ? (
|
||||
<form className="space-y-6 mt-4" onSubmit={handleSignup}>
|
||||
{error && (
|
||||
<div className="p-3 bg-red-50 border border-red-200 rounded-lg">
|
||||
<p className="text-sm text-red-800">{error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Full Name Field */}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="signup-fullName" className="text-sm font-medium text-black">
|
||||
Full Name *
|
||||
</label>
|
||||
<Input
|
||||
id="signup-fullName"
|
||||
type="text"
|
||||
placeholder="John Doe"
|
||||
value={signupData.fullName}
|
||||
onChange={(e) => setSignupData({ ...signupData, fullName: e.target.value })}
|
||||
className="h-12 bg-white border-gray-300"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Email Field */}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="signup-email" className="text-sm font-medium text-black">
|
||||
Email address *
|
||||
</label>
|
||||
<Input
|
||||
id="signup-email"
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
value={signupData.email}
|
||||
onChange={(e) => setSignupData({ ...signupData, email: e.target.value })}
|
||||
className="h-12 bg-white border-gray-300"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Phone Field */}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="signup-phone" className="text-sm font-medium text-black">
|
||||
Phone Number *
|
||||
</label>
|
||||
<Input
|
||||
id="signup-phone"
|
||||
type="tel"
|
||||
placeholder="+1 (555) 123-4567"
|
||||
value={signupData.phone}
|
||||
onChange={(e) => setSignupData({ ...signupData, phone: e.target.value })}
|
||||
className="h-12 bg-white border-gray-300"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={signupLoading}
|
||||
className="w-full h-12 text-base font-semibold bg-linear-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{signupLoading ? (
|
||||
<>
|
||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||
Creating account...
|
||||
</>
|
||||
) : (
|
||||
"Sign up"
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{/* Switch to Login */}
|
||||
<p className="text-sm text-gray-600 text-center">
|
||||
Already have an account?{" "}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSwitchToLogin}
|
||||
className="text-blue-600 underline font-medium hover:text-blue-700"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
) : (
|
||||
/* Login Form */
|
||||
<form className="space-y-6 mt-4" onSubmit={handleLogin}>
|
||||
{error && (
|
||||
<div className="p-3 bg-red-50 border border-red-200 rounded-lg">
|
||||
<p className="text-sm text-red-800">{error}</p>
|
||||
@ -144,26 +270,28 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
|
||||
/>
|
||||
<span className="text-black">Remember me</span>
|
||||
</label>
|
||||
<Link
|
||||
href="/forgot-password"
|
||||
<button
|
||||
type="button"
|
||||
className="text-blue-600 hover:text-blue-700 font-medium"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onOpenChange(false);
|
||||
}}
|
||||
onClick={() => onOpenChange(false)}
|
||||
>
|
||||
Forgot password?
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Sign Up Prompt */}
|
||||
<p className="text-sm text-gray-600 text-center">
|
||||
New to Attune Heart Therapy?{" "}
|
||||
<Link href="/signup" className="text-blue-600 underline font-medium">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSwitchToSignup}
|
||||
className="text-blue-600 underline font-medium hover:text-blue-700"
|
||||
>
|
||||
Sign up
|
||||
</Link>
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user