first commit

This commit is contained in:
AnuragJangid18 2026-03-30 17:24:23 +05:30
commit 44995cb5db
60 changed files with 5472 additions and 0 deletions

View file

@ -0,0 +1,232 @@
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;