Skip to content

Commit

Permalink
Add temporary landing page
Browse files Browse the repository at this point in the history
  • Loading branch information
brendantwh committed Oct 15, 2024
1 parent 1700ebd commit 0a3fc9f
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 158 deletions.
2 changes: 1 addition & 1 deletion frontend/app/(authenticated)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function AuthenticatedLayout({
<DropdownMenuLabel>Username</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild><Link href="/profile" className="cursor-pointer"><User className="mr-2 h-4 w-4" />Profile</Link></DropdownMenuItem>
<DropdownMenuItem className="cursor-pointer"><LogOut className="mr-2 h-4 w-4" />Log out</DropdownMenuItem>
<DropdownMenuItem asChild><Link href="/" className="cursor-pointer"><LogOut className="mr-2 h-4 w-4" />Log out</Link></DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</nav>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/forgot-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export default function ForgotPassword() {
<div className="flex flex-col min-h-screen w-screen px-10 items-start justify-center bg-white font-sans">
<div className="-mt-80 mx-auto flex flex-col justify-center gap-6 w-[350px]">
<div className="pb-10">
<Button asChild variant="ghost" size="sm" className="pl-0 py-1 pr-2 -ml-1"><Link href="/" className="text-muted-foreground"><ChevronLeft className="h-5 w-5" />Back to Login</Link></Button>
<Button asChild variant="ghost" size="sm" className="pl-0 py-1 pr-2 -ml-1"><Link href="/login" className="text-muted-foreground"><ChevronLeft className="h-5 w-5" />Back to Login</Link></Button>
</div>
<div className="flex flex-col gap-2 text-left">
<span className="font-serif font-light text-4xl text-primary tracking-tight">
Expand Down
161 changes: 161 additions & 0 deletions frontend/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
"use client"

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import Link from "next/link";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { useRouter } from "next/navigation"
import { useState } from "react";
import { AlertCircle, LoaderCircle } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";

const formSchema = z.object({
email: z.string().min(1, "Email is required").email({ message: "Invalid email address" }),
password: z.string().min(8, "Password requires at least 8 characters"), // Password has more criterias but we only let user know about length
})

export default function Login() {
const router = useRouter()
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
});

async function onSubmit(values: z.infer<typeof formSchema>) {
// Placeholder for auth to user service
try {
await form.trigger();
if (!form.formState.isValid) {
return;
}

setIsLoading(true);

const response = await fetch(`${process.env.NEXT_PUBLIC_USER_API_AUTH_URL}/login`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(values),
});

if (response.status == 400) {
setError("Missing email or password.");
throw new Error("Missing email or password: " + response.statusText);
} else if (response.status == 401) {
setError("Incorrect email or password.");
throw new Error("Incorrect email or password: " + response.statusText);
} else if (response.status == 500) {
setError("Database or server error. Please try again.");
throw new Error("Database or server error: " + response.statusText);
} else if (!response.ok) {
setError("There was an error logging in. Please try again.");
throw new Error("Error logging in: " + response.statusText);
}

const responseData = await response.json();
console.log(responseData.data["accessToken"]);
router.push("/question-repo");
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
}

return (
<div className="flex min-h-screen w-screen -mt-20 px-10 items-center justify-center bg-white font-sans">
<div className="mx-auto flex flex-col justify-center gap-6 w-[350px]">
<div className="flex flex-col gap-2 text-left pb-1">
<span className="font-serif font-light text-4xl text-primary tracking-tight">
Sign in
</span>
</div>
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle className="font-semibold">Error</AlertTitle>
<AlertDescription>
{error}
</AlertDescription>
</Alert>
)}
<div className="flex flex-col gap-4 text-black">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
<div className="flex justify-between">
<span>Password</span>
<Link href="/forgot-password" className="underline underline-offset-2">
Forgot password?
</Link>
</div>
</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button
type="submit"
className="btn btn-primary w-full mt-2 disabled:opacity-80"
disabled={isLoading}
>
{isLoading ? (
<LoaderCircle className="animate-spin" />
) : (
"Sign in"
)}
</Button>
</form>
</Form>
<div className="px-8 text-center text-sm">
Don&apos;t have an account?{" "}
<Link
href="/signup"
className="font-semibold hover:text-brand-700 transition-colors underline underline-offset-2"
>
Sign up
</Link>
</div>
</div>
</div>
</div>
)
}
173 changes: 20 additions & 153 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,160 +1,27 @@
"use client"

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import Link from "next/link";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { useRouter } from "next/navigation"
import { useState } from "react";
import { AlertCircle, LoaderCircle } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";

const formSchema = z.object({
email: z.string().min(1, "Email is required").email({ message: "Invalid email address" }),
password: z.string().min(8, "Password requires at least 8 characters"), // Password has more criterias but we only let user know about length
})

export default function Login() {
const router = useRouter()
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
});

async function onSubmit(values: z.infer<typeof formSchema>) {
// Placeholder for auth to user service
try {
await form.trigger();
if (!form.formState.isValid) {
return;
}

setIsLoading(true);

const response = await fetch(`${process.env.NEXT_PUBLIC_USER_API_AUTH_URL}/login`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(values),
});

if (response.status == 400) {
setError("Missing email or password.");
throw new Error("Missing email or password: " + response.statusText);
} else if (response.status == 401) {
setError("Incorrect email or password.");
throw new Error("Incorrect email or password: " + response.statusText);
} else if (response.status == 500) {
setError("Database or server error. Please try again.");
throw new Error("Database or server error: " + response.statusText);
} else if (!response.ok) {
setError("There was an error logging in. Please try again.");
throw new Error("Error logging in: " + response.statusText);
}

const responseData = await response.json();
console.log(responseData.data["accessToken"]);
router.push("/question-repo");
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
}

export default function Landing() {
return (
<div className="flex min-h-screen w-screen -mt-20 px-10 items-center justify-center bg-white font-sans">
<div className="mx-auto flex flex-col justify-center gap-6 w-[350px]">
<div className="flex flex-col gap-2 text-left pb-1">
<span className="font-serif font-light text-4xl text-primary tracking-tight">
Sign in
</span>
</div>
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle className="font-semibold">Error</AlertTitle>
<AlertDescription>
{error}
</AlertDescription>
</Alert>
)}
<div className="flex flex-col gap-4 text-black">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
<div className="flex justify-between">
<span>Password</span>
<Link href="/forgot-password" className="underline underline-offset-2">
Forgot password?
</Link>
</div>
</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button
type="submit"
className="btn btn-primary w-full mt-2 disabled:opacity-80"
disabled={isLoading}
>
{isLoading ? (
<LoaderCircle className="animate-spin" />
) : (
"Sign in"
)}
</Button>
</form>
</Form>
<div className="px-8 text-center text-sm">
Don&apos;t have an account?{" "}
<Link
href="/signup"
className="font-semibold hover:text-brand-700 transition-colors underline underline-offset-2"
>
Sign up
</Link>
</div>
</div>
<div className="flex flex-col min-h-screen w-screen gap-12 -mt-20 px-10 items-center justify-center bg-white font-sans">
<p className="font-bold font-brand tracking-tight text-brand-700 text-5xl">PeerPrep</p>
<p className="text-primary text-lg">Temporary landing page with all the links</p>
<div className="flex gap-8">
<Button asChild variant="outline" size="lg" className="border-brand-300 hover:border-brand-100 text-brand-600">
<Link href="/login" className="text-primary">Login</Link>
</Button>
<Button asChild size="lg" className="bg-brand-600 hover:bg-brand-600/90">
<Link href="/signup" className="text-white">Sign Up</Link>
</Button>
</div>
<div className="flex gap-8">
<Link href="/forgot-password" className="text-primary underline underline-offset-4">Forgot password (enter email for link)</Link>
<Link href="/reset-password" className="text-primary underline underline-offset-4">Reset password (enter password to reset)</Link>
<Link href="/profile" className="text-primary underline underline-offset-4">Profile page</Link>
</div>
<div className="flex gap-8">
<Link href="/questions" className="text-primary underline underline-offset-4">Questions (user facing)</Link>
<Link href="/question-repo" className="text-primary underline underline-offset-4">Question Repo (CRUD)</Link>
</div>
</div>
)
Expand Down
3 changes: 1 addition & 2 deletions frontend/app/reset-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { useRouter } from "next/navigation"
import { useEffect, useState } from "react";
import { AlertCircle, LoaderCircle, TriangleAlert } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
Expand Down Expand Up @@ -124,7 +123,7 @@ export default function ResetPassword() {
<AlertCircle className="h-4 w-4" />
<AlertTitle className="font-semibold">Password has been reset</AlertTitle>
<AlertDescription>
<Link href="/" className="underline underline-offset-2">Login here</Link> with your new password.
<Link href="/login" className="underline underline-offset-2">Login here</Link> with your new password.
</AlertDescription>
</Alert>
)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export default function Signup() {
<div className="px-8 text-center text-sm">
Already have an account?{" "}
<Link
href="/"
href="/login"
className="font-semibold hover:text-brand-700 transition-colors underline underline-offset-2"
>
Sign in
Expand Down

0 comments on commit 0a3fc9f

Please sign in to comment.