diff --git a/teressa-copeland-homes/public/red.jpg b/teressa-copeland-homes/public/red.jpg new file mode 100644 index 0000000..0c4c252 Binary files /dev/null and b/teressa-copeland-homes/public/red.jpg differ diff --git a/teressa-copeland-homes/src/app/agent/login/PasswordField.tsx b/teressa-copeland-homes/src/app/agent/login/PasswordField.tsx new file mode 100644 index 0000000..016b0be --- /dev/null +++ b/teressa-copeland-homes/src/app/agent/login/PasswordField.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { useState } from "react"; + +export function PasswordField() { + const [showPassword, setShowPassword] = useState(false); + + return ( +
+ +
+ + +
+
+ ); +} diff --git a/teressa-copeland-homes/src/app/agent/login/page.tsx b/teressa-copeland-homes/src/app/agent/login/page.tsx new file mode 100644 index 0000000..ba33734 --- /dev/null +++ b/teressa-copeland-homes/src/app/agent/login/page.tsx @@ -0,0 +1,162 @@ +import Image from "next/image"; +import { redirect } from "next/navigation"; +import { AuthError } from "next-auth"; +import { signIn } from "@/lib/auth"; +import { PasswordField } from "./PasswordField"; + +async function loginAction(formData: FormData) { + "use server"; + try { + await signIn("credentials", { + email: formData.get("email") as string, + password: formData.get("password") as string, + redirectTo: "/agent/dashboard", + }); + } catch (error) { + // CRITICAL: Only catch AuthError. Everything else (including NEXT_REDIRECT) must re-throw. + if (error instanceof AuthError) { + redirect("/agent/login?error=invalid"); + } + throw error; // Re-throws NEXT_REDIRECT — allows the redirect to fire + } +} + +interface LoginPageProps { + searchParams: Promise<{ error?: string; signed_out?: string }>; +} + +export default async function LoginPage({ searchParams }: LoginPageProps) { + const params = await searchParams; + const hasError = params.error === "invalid"; + const signedOut = params.signed_out === "1"; + + return ( +
+ {/* Left side: branded photo panel — hidden on mobile */} +
+ Teressa Copeland + {/* Dark gradient overlay */} +
+ {/* Brand name text */} +
+

+ Agent Portal +

+

+ Teressa Copeland Homes +

+

+ Utah real estate expertise +

+
+
+ + {/* Right side: login form */} +
+
+ {/* Mobile brand header */} +
+

+ Teressa Copeland Homes +

+
+ + {/* Card */} +
+

+ Agent Portal +

+ + {/* Signed-out confirmation banner */} + {signedOut && ( +
+ You've been signed out. +
+ )} + + {/* Error banner */} + {hasError && ( +
+ Invalid email or password. +
+ )} + +
+ {/* Email field */} +
+ + +
+ + {/* Password field — client component for show/hide toggle */} + + + {/* Submit button */} + + +
+
+
+
+ ); +}