-
Notifications
You must be signed in to change notification settings - Fork 0
AUTH-14 Created basic UI components for Login Page #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| "use client"; | ||
| import { useState } from "react"; | ||
|
|
||
| interface Props { | ||
| onNext: () => void; | ||
| } | ||
|
|
||
| export function EmailForm({ onNext }: Props) { | ||
| const [email, setEmail] = useState(""); | ||
|
|
||
| function handleSubmit(e: React.SubmitEvent) { | ||
| e.preventDefault(); | ||
| onNext(); | ||
| } | ||
|
|
||
| return ( | ||
| <form onSubmit={handleSubmit} className="w-125 bg-white flex flex-col items-center justify-center p-8 text-xl rounded-4xl shadow-lg"> | ||
| <input | ||
| className="w-full p-4 m-4 bg-gray-200 rounded-lg" | ||
| type="email" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth adding |
||
| placeholder="you@example.com" | ||
| value={email} | ||
| onChange={(e) => setEmail(e.target.value)} | ||
| required | ||
| /> | ||
| <button | ||
| className="w-80 p-2 pl-4 pr-4 m-4 rounded-4xl" | ||
| type="submit" | ||
| > | ||
| Send Code | ||
| </button> | ||
| </form> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| "use client"; | ||
| import { useState, useEffect } from "react"; | ||
|
|
||
| interface Props { | ||
| onResend: () => void; | ||
| } | ||
|
|
||
| export function OtpForm({ onResend }: Props) { | ||
| const [otp, setOtp] = useState(""); | ||
| const [cooldown, setCooldown] = useState(15); | ||
|
|
||
| useEffect(() => { | ||
| if (cooldown <= 0) return; | ||
| const t = setTimeout(() => setCooldown((c) => c - 1), 1000); | ||
| return () => clearTimeout(t); | ||
| }, [cooldown]); | ||
|
|
||
| function handleSubmit(e: React.SubmitEvent) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming this is intentional for a UI-only stub (nothing in this PR wires up |
||
| e.preventDefault(); | ||
| } | ||
|
|
||
| function handleResend() { | ||
| onResend(); | ||
| setCooldown(15); | ||
| } | ||
|
|
||
| return ( | ||
| <form onSubmit={handleSubmit} className="w-125 bg-white flex flex-col items-center justify-center p-8 text-xl rounded-4xl shadow-lg"> | ||
| <input | ||
| className="w-full p-4 m-4 bg-gray-200 rounded-lg tracking-widest text-center" | ||
| type="text" | ||
| placeholder="XXXXXX" | ||
| maxLength={6} | ||
| value={otp} | ||
| onChange={(e) => setOtp(e.target.value)} | ||
| required | ||
| /> | ||
| <button | ||
| className="w-80 p-2 pl-4 pr-4 m-4 rounded-4xl" | ||
| type="submit" | ||
| > | ||
| Verify Code | ||
| </button> | ||
| <button | ||
| type="button" | ||
| onClick={handleResend} | ||
| disabled={cooldown > 0} | ||
| className="text-sm text-gray-400 disabled:opacity-50" | ||
| > | ||
| {cooldown > 0 ? `Resend code in ${cooldown}s` : "Resend code"} | ||
| </button> | ||
| </form> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| "use client"; | ||
| import Image from "next/image"; | ||
| import { useState } from "react"; | ||
| import { EmailForm } from "./EmailForm"; | ||
| import { OtpForm } from "./OtpForm"; | ||
|
|
||
| type Step = "email" | "otp"; | ||
|
|
||
| export default function LoginPage() { | ||
| const [step, setStep] = useState<Step>("email"); | ||
|
|
||
| return ( | ||
| <main className="min-h-screen bg-gradient-to-b from-white to-red-200"> | ||
| <div className="flex flex-col items-center justify-center"> | ||
| <Image className="m-8" src="/SGA_logo.png" alt="Logo" width={350} height={150} style={{ height: "auto" }} loading="eager" /> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small but will bite in prod: this references |
||
| <div className="flex flex-col items-center justify-center pt-4"> | ||
| <h1 className="font-bold text-4xl m-8">Login</h1> | ||
| {step === "email" ? ( | ||
| <EmailForm onNext={() => setStep("otp")} /> | ||
| ) : ( | ||
| <OtpForm onResend={() => {}} /> | ||
| )} | ||
| </div> | ||
| </div> | ||
| </main> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are bare element selectors (
h1,button) added outside the existing@layer baseblock above, so under CSS cascade-layer rules they'll take precedence over any Tailwind utility class on a button or h1 anywhere else in the app — not just this login page — and they don't participate in the dark-mode variables already defined earlier in this file. Scoping this to the two buttons on the login page (Tailwind utility classes, or a.btn-primaryclass) would avoid the app-wide side effect.