232 lines
11 KiB
JavaScript
232 lines
11 KiB
JavaScript
import React, { useState } from "react";
|
|
import { useGoogleLogin } from "@react-oauth/google";
|
|
import { api } from "../../lib/api";
|
|
|
|
const PhoneInputScreen = ({ onRequestOtp, onCancel, onGoogleSuccess, onRegisterSuccess }) => {
|
|
const [activeTab, setActiveTab] = useState("login");
|
|
|
|
// Register Form State
|
|
const [name, setName] = useState("");
|
|
const [email, setEmail] = useState("");
|
|
const [phone, setPhone] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
|
|
const [isRegistering, setIsRegistering] = useState(false);
|
|
const [errorMsg, setErrorMsg] = useState("");
|
|
|
|
const login = useGoogleLogin({
|
|
onSuccess: onGoogleSuccess,
|
|
onError: () => alert("Login Failed")
|
|
});
|
|
|
|
const handleRegister = async () => {
|
|
if (!name || !email || !phone || !password) {
|
|
setErrorMsg("Please fill all fields.");
|
|
return;
|
|
}
|
|
|
|
setIsRegistering(true);
|
|
setErrorMsg("");
|
|
|
|
try {
|
|
// Connects cleanly with the api configuration defined by VITE_API_URL or defaulted to local proxy.
|
|
const response = await api.post("/api/auth/register", {
|
|
name,
|
|
email,
|
|
phone,
|
|
password,
|
|
});
|
|
|
|
// Pass the successful name/email down the line dynamically
|
|
onRegisterSuccess({ name: response.user?.name || name, email: response.user?.email || email, phone: response.user?.phone || phone });
|
|
|
|
} catch (err) {
|
|
if (err.message.includes("409") || err.message.toLowerCase().includes("conflict") || err.message.toLowerCase().includes("already registered")) {
|
|
setErrorMsg("Email already registered. Did you mean to log in?");
|
|
} else {
|
|
setErrorMsg(err.message || "Registration failed. Please try again.");
|
|
}
|
|
} finally {
|
|
setIsRegistering(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col md:flex-row w-full h-full sm:h-[450px]">
|
|
{/* Left Promo Column */}
|
|
<div className="hidden md:flex flex-col md:w-5/12 relative rounded-l-2xl overflow-hidden bg-dark-900">
|
|
<img
|
|
src="https://images.unsplash.com/photo-1549317661-bd32c8ce0db2?auto=format&fit=crop&q=80&w=800"
|
|
alt="Steering wheel"
|
|
className="absolute inset-0 w-full h-full object-cover opacity-60 mix-blend-overlay"
|
|
/>
|
|
<div className="relative z-10 flex flex-col justify-end h-full p-8 pb-10 bg-gradient-to-t from-black/80 to-transparent">
|
|
<h2 className="text-4xl font-extrabold text-white mb-2 leading-tight">10% OFF<br />
|
|
<span className="text-xl font-bold">on your first booking!</span>
|
|
</h2>
|
|
<p className="text-sm text-gray-300 mb-6">
|
|
Use the coupon below to get flat 10% OFF on your first booking with road.rentals.
|
|
</p>
|
|
<div className="flex items-center justify-between border border-white/20 rounded-xl px-4 py-3 bg-black/40 backdrop-blur-md">
|
|
<span className="text-white font-mono font-bold tracking-wider">RE1ST10</span>
|
|
<button className="text-white hover:text-primary-400 transition-colors">
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Auth Column */}
|
|
<div className="flex-1 p-6 sm:p-10 flex flex-col justify-center bg-white rounded-r-2xl animate-fadeInUp overflow-y-auto">
|
|
|
|
{/* Tab Switcher */}
|
|
<div className="flex bg-gray-100 rounded-xl p-1 mb-8 w-full max-w-[280px]">
|
|
<button
|
|
onClick={() => setActiveTab("login")}
|
|
className={`flex-1 text-sm font-bold py-2 rounded-lg transition-all ${activeTab === 'login' ? 'bg-white text-dark-900 shadow-sm' : 'text-gray-500 hover:text-dark-700'}`}
|
|
>
|
|
Log In
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab("register")}
|
|
className={`flex-1 text-sm font-bold py-2 rounded-lg transition-all ${activeTab === 'register' ? 'bg-white text-dark-900 shadow-sm' : 'text-gray-500 hover:text-dark-700'}`}
|
|
>
|
|
Register
|
|
</button>
|
|
</div>
|
|
|
|
{activeTab === "login" ? (
|
|
<>
|
|
<h2 className="text-2xl font-bold text-dark-900 mb-2">Welcome Back</h2>
|
|
<p className="text-sm text-dark-500 mb-8 leading-relaxed">
|
|
Sign in to book your rides, manage trips, and enjoy a seamless travel experience
|
|
</p>
|
|
|
|
{/* Phone Input Box */}
|
|
<div className="flex rounded-xl border border-gray-300 focus-within:border-primary-600 focus-within:ring-1 focus-within:ring-primary-600 transition-all mb-6">
|
|
<div className="flex flex-shrink-0 items-center gap-1.5 px-4 bg-gray-50 border-r border-gray-300 rounded-l-xl">
|
|
<span className="text-xl">🇮🇳</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-dark-700" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
|
|
</div>
|
|
<input
|
|
type="tel"
|
|
placeholder="Phone number"
|
|
className="flex-1 w-full outline-none px-4 py-3.5 text-sm font-semibold rounded-r-xl placeholder:font-normal"
|
|
/>
|
|
</div>
|
|
|
|
{/* Buttons Row */}
|
|
<div className="grid grid-cols-2 gap-3 mb-6">
|
|
<button
|
|
onClick={onCancel}
|
|
className="w-full bg-gray-50 border border-gray-200 hover:bg-gray-100 text-dark-900 font-bold text-sm py-3.5 rounded-xl transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
onClick={onRequestOtp}
|
|
className="w-full bg-primary-600 hover:bg-primary-700 text-white font-bold text-sm py-3.5 rounded-xl transition-colors"
|
|
>
|
|
Request OTP
|
|
</button>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<h2 className="text-2xl font-bold text-dark-900 mb-2">Create an Account</h2>
|
|
<p className="text-sm text-dark-500 mb-6 leading-relaxed">
|
|
Register now to start your reliable travel journey with road.rentals
|
|
</p>
|
|
|
|
{/* Register Fields */}
|
|
<div className="space-y-4 mb-6">
|
|
<input
|
|
type="text"
|
|
placeholder="Full Name"
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
className="w-full rounded-xl border border-gray-300 focus:border-primary-600 focus:ring-1 focus:ring-primary-600 outline-none px-4 py-3.5 text-sm transition-all"
|
|
/>
|
|
<input
|
|
type="email"
|
|
placeholder="Email Address"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
className="w-full rounded-xl border border-gray-300 focus:border-primary-600 focus:ring-1 focus:ring-primary-600 outline-none px-4 py-3.5 text-sm transition-all"
|
|
/>
|
|
|
|
<div className="flex rounded-xl border border-gray-300 focus-within:border-primary-600 focus-within:ring-1 focus-within:ring-primary-600 transition-all">
|
|
<div className="flex flex-shrink-0 items-center gap-1.5 px-4 bg-gray-50 border-r border-gray-300 rounded-l-xl">
|
|
<span className="text-xl">🇮🇳</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-dark-700" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
|
|
</div>
|
|
<input
|
|
type="tel"
|
|
placeholder="Mobile Number"
|
|
value={phone}
|
|
onChange={(e) => setPhone(e.target.value)}
|
|
className="flex-1 w-full outline-none px-4 py-3.5 text-sm font-semibold rounded-r-xl placeholder:font-normal"
|
|
/>
|
|
</div>
|
|
|
|
<input
|
|
type="password"
|
|
placeholder="Secure Password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
className="w-full rounded-xl border border-gray-300 focus:border-primary-600 focus:ring-1 focus:ring-primary-600 outline-none px-4 py-3.5 text-sm transition-all"
|
|
/>
|
|
|
|
{errorMsg && (
|
|
<div className="text-red-500 text-sm font-medium mt-2 px-1">
|
|
{errorMsg}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Buttons Row */}
|
|
<div className="grid grid-cols-2 gap-3 mb-6">
|
|
<button
|
|
onClick={onCancel}
|
|
className="w-full bg-gray-50 border border-gray-200 hover:bg-gray-100 text-dark-900 font-bold text-sm py-3.5 rounded-xl transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
onClick={handleRegister}
|
|
disabled={isRegistering}
|
|
className="w-full bg-primary-600 hover:bg-primary-700 text-white font-bold text-sm py-3.5 rounded-xl transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{isRegistering ? "Creating Account..." : "Create Account"}
|
|
</button>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* Divider */}
|
|
<div className="relative flex items-center mb-6">
|
|
<div className="flex-grow border-t border-gray-100"></div>
|
|
<span className="flex-shrink-0 mx-4 text-gray-400 text-sm">or</span>
|
|
<div className="flex-grow border-t border-gray-100"></div>
|
|
</div>
|
|
|
|
{/* Google Btn */}
|
|
<button
|
|
onClick={() => login()}
|
|
className="w-full flex items-center justify-center gap-3 bg-gray-50 border border-dark-200 hover:bg-gray-100 text-dark-900 font-bold text-sm py-3.5 rounded-xl transition-colors"
|
|
>
|
|
<svg className="w-5 h-5" viewBox="0 0 48 48">
|
|
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" />
|
|
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" />
|
|
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z" />
|
|
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" />
|
|
</svg>
|
|
Login with Google
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PhoneInputScreen;
|