feat/deliverables #22

Merged
Hammond merged 2 commits from feat/deliverables into master 2025-11-24 22:10:30 +00:00
2 changed files with 12 additions and 205 deletions
Showing only changes of commit 3465961819 - Show all commits

View File

@ -375,31 +375,12 @@ function LoginContent() {
{/* Heading */} {/* Heading */}
<h1 className="text-3xl font-bold bg-linear-to-r from-rose-600 via-pink-600 to-rose-600 bg-clip-text text-transparent mb-2"> <h1 className="text-3xl font-bold bg-linear-to-r from-rose-600 via-pink-600 to-rose-600 bg-clip-text text-transparent mb-2">
{step === "login" && "Welcome back"} {step === "login" && "Welcome back"}
{step === "signup" && "Create an account"}
{step === "verify" && "Verify your email"} {step === "verify" && "Verify your email"}
</h1> </h1>
{/* Subtitle */} {/* Subtitle */}
{step === "login" && ( {step === "login" && (
<p className={`mb-6 ${isDark ? 'text-gray-400' : 'text-gray-600'}`}> <p className={`mb-6 ${isDark ? 'text-gray-400' : 'text-gray-600'}`}>
New to Attune Heart Therapy?{" "} Sign in to access your admin dashboard
<Link
href="/signup"
className={`underline font-medium ${isDark ? 'text-blue-400 hover:text-blue-300' : 'text-blue-600 hover:text-blue-700'}`}
>
Sign up
</Link>
</p>
)}
{step === "signup" && (
<p className={`mb-6 ${isDark ? 'text-gray-400' : 'text-gray-600'}`}>
Already have an account?{" "}
<button
type="button"
onClick={() => setStep("login")}
className={`underline font-medium ${isDark ? 'text-blue-400 hover:text-blue-300' : 'text-blue-600 hover:text-blue-700'}`}
>
Log in
</button>
</p> </p>
)} )}
{step === "verify" && registeredEmail && ( {step === "verify" && registeredEmail && (
@ -519,168 +500,6 @@ function LoginContent() {
</form> </form>
)} )}
{/* Signup Form */}
{step === "signup" && (
<form className="space-y-4" onSubmit={handleSignup}>
{/* First Name Field */}
<div className="space-y-2">
<label htmlFor="firstName" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
First Name *
</label>
<Input
id="firstName"
type="text"
placeholder="John"
value={signupData.first_name}
onChange={(e) => handleSignupChange("first_name", e.target.value)}
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'} ${errors.first_name ? 'border-red-500' : ''}`}
required
/>
{errors.first_name && (
<p className="text-sm text-red-500">{errors.first_name}</p>
)}
</div>
{/* Last Name Field */}
<div className="space-y-2">
<label htmlFor="lastName" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
Last Name *
</label>
<Input
id="lastName"
type="text"
placeholder="Doe"
value={signupData.last_name}
onChange={(e) => handleSignupChange("last_name", e.target.value)}
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'} ${errors.last_name ? 'border-red-500' : ''}`}
required
/>
{errors.last_name && (
<p className="text-sm text-red-500">{errors.last_name}</p>
)}
</div>
{/* Email Field */}
<div className="space-y-2">
<label htmlFor="signup-email" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
Email address *
</label>
<Input
id="signup-email"
type="email"
placeholder="Email address"
value={signupData.email}
onChange={(e) => handleSignupChange("email", e.target.value)}
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'} ${errors.email ? 'border-red-500' : ''}`}
required
/>
{errors.email && (
<p className="text-sm text-red-500">{errors.email}</p>
)}
</div>
{/* Phone Field */}
<div className="space-y-2">
<label htmlFor="phone" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
Phone Number (Optional)
</label>
<Input
id="phone"
type="tel"
placeholder="+1 (555) 123-4567"
value={signupData.phone_number || ""}
onChange={(e) => handleSignupChange("phone_number", e.target.value)}
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'}`}
/>
</div>
{/* Password Field */}
<div className="space-y-2">
<label htmlFor="signup-password" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
Password *
</label>
<div className="relative">
<Input
id="signup-password"
type={showPassword ? "text" : "password"}
placeholder="Password (min 8 characters)"
value={signupData.password}
onChange={(e) => handleSignupChange("password", e.target.value)}
className={`h-11 pr-12 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'} ${errors.password ? 'border-red-500' : ''}`}
required
/>
<Button
type="button"
variant="ghost"
size="icon"
onClick={() => setShowPassword(!showPassword)}
className={`absolute right-4 top-1/2 -translate-y-1/2 h-auto w-auto p-0 ${isDark ? 'text-gray-400 hover:text-gray-300' : 'text-gray-500 hover:text-gray-700'}`}
aria-label={showPassword ? "Hide password" : "Show password"}
>
{showPassword ? (
<EyeOff className="w-5 h-5" />
) : (
<Eye className="w-5 h-5" />
)}
</Button>
</div>
{errors.password && (
<p className="text-sm text-red-500">{errors.password}</p>
)}
</div>
{/* Confirm Password Field */}
<div className="space-y-2">
<label htmlFor="signup-password2" className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-black'}`}>
Confirm Password *
</label>
<div className="relative">
<Input
id="signup-password2"
type={showPassword2 ? "text" : "password"}
placeholder="Confirm password"
value={signupData.password2}
onChange={(e) => handleSignupChange("password2", e.target.value)}
className={`h-11 pr-12 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'} ${errors.password2 ? 'border-red-500' : ''}`}
required
/>
<Button
type="button"
variant="ghost"
size="icon"
onClick={() => setShowPassword2(!showPassword2)}
className={`absolute right-4 top-1/2 -translate-y-1/2 h-auto w-auto p-0 ${isDark ? 'text-gray-400 hover:text-gray-300' : 'text-gray-500 hover:text-gray-700'}`}
aria-label={showPassword2 ? "Hide password" : "Show password"}
>
{showPassword2 ? (
<EyeOff className="w-5 h-5" />
) : (
<Eye className="w-5 h-5" />
)}
</Button>
</div>
{errors.password2 && (
<p className="text-sm text-red-500">{errors.password2}</p>
)}
</div>
{/* Submit Button */}
<Button
type="submit"
disabled={registerMutation.isPending}
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 mt-6"
>
{registerMutation.isPending ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
Creating account...
</>
) : (
"Sign up"
)}
</Button>
</form>
)}
{/* OTP Verification Form */} {/* OTP Verification Form */}
{step === "verify" && ( {step === "verify" && (
@ -775,17 +594,17 @@ function LoginContent() {
)} )}
</Button> </Button>
{/* Back to signup */} {/* Back to login */}
<div className="text-center"> <div className="text-center">
<button <button
type="button" type="button"
onClick={() => { onClick={() => {
setStep("signup"); setStep("login");
setOtpData({ email: "", otp: "" }); setOtpData({ email: "", otp: "" });
}} }}
className={`text-sm font-medium ${isDark ? 'text-gray-400 hover:text-gray-300' : 'text-gray-600 hover:text-gray-700'}`} className={`text-sm font-medium ${isDark ? 'text-gray-400 hover:text-gray-300' : 'text-gray-600 hover:text-gray-700'}`}
> >
Back to signup Back to login
</button> </button>
</div> </div>
</form> </form>

View File

@ -55,7 +55,7 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
const validation = loginSchema.safeParse(loginData); const validation = loginSchema.safeParse(loginData);
if (!validation.success) { if (!validation.success) {
const firstError = validation.error.issues[0]; const firstError = validation.error.issues[0];
setError(firstError.message); toast.error(firstError.message);
return; return;
} }
@ -70,7 +70,6 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
} }
} catch (err) { } catch (err) {
const errorMessage = err instanceof Error ? err.message : "Login failed. Please try again."; const errorMessage = err instanceof Error ? err.message : "Login failed. Please try again.";
setError(errorMessage);
toast.error(errorMessage); toast.error(errorMessage);
} }
}; };
@ -83,7 +82,7 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
const validation = registerSchema.safeParse(signupData); const validation = registerSchema.safeParse(signupData);
if (!validation.success) { if (!validation.success) {
const firstError = validation.error.issues[0]; const firstError = validation.error.issues[0];
setError(firstError.message); toast.error(firstError.message);
return; return;
} }
@ -106,7 +105,6 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
} }
} catch (err) { } catch (err) {
const errorMessage = err instanceof Error ? err.message : "Signup failed. Please try again."; const errorMessage = err instanceof Error ? err.message : "Signup failed. Please try again.";
setError(errorMessage);
toast.error(errorMessage); toast.error(errorMessage);
} }
}; };
@ -163,11 +161,6 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
{/* Signup Form */} {/* Signup Form */}
{isSignup ? ( {isSignup ? (
<form className="space-y-4 sm:space-y-5 py-4 sm:py-6" onSubmit={handleSignup}> <form className="space-y-4 sm:space-y-5 py-4 sm:py-6" onSubmit={handleSignup}>
{error && (
<div className={`p-3 rounded-lg border ${isDark ? 'bg-red-900/20 border-red-800' : 'bg-red-50 border-red-200'}`}>
<p className={`text-sm ${isDark ? 'text-red-200' : 'text-red-800'}`}>{error}</p>
</div>
)}
{/* First Name Field */} {/* First Name Field */}
<div className="space-y-1.5 sm:space-y-2"> <div className="space-y-1.5 sm:space-y-2">
@ -327,11 +320,6 @@ export function LoginDialog({ open, onOpenChange, onLoginSuccess }: LoginDialogP
) : ( ) : (
/* Login Form */ /* Login Form */
<form className="space-y-4 sm:space-y-5 py-4 sm:py-6" onSubmit={handleLogin}> <form className="space-y-4 sm:space-y-5 py-4 sm:py-6" onSubmit={handleLogin}>
{error && (
<div className={`p-3 rounded-lg border ${isDark ? 'bg-red-900/20 border-red-800' : 'bg-red-50 border-red-200'}`}>
<p className={`text-sm ${isDark ? 'text-red-200' : 'text-red-800'}`}>{error}</p>
</div>
)}
{/* Email Field */} {/* Email Field */}
<div className="space-y-1.5 sm:space-y-2"> <div className="space-y-1.5 sm:space-y-2">