Skip to content

Commit

Permalink
add login and logout functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
StephDietz committed Mar 13, 2024
1 parent 6f174a9 commit d01cdfb
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 22 deletions.
12 changes: 10 additions & 2 deletions app/(public)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
'use client';

import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import Link from 'next/link';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { login } from '@/lib/auth';
import { useFormState, useFormStatus } from 'react-dom';

export default function Login() {
const [state, action] = useFormState(login, undefined);

return (
<div className="flex w-1/4 items-center px-4 sm:px-6 lg:px-8">
<div className="mx-auto w-full space-y-8">
Expand All @@ -14,12 +20,13 @@ export default function Login() {
Enter your email below to login to your account
</p>
</div>
<form>
<form action={action}>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
name="email"
placeholder="[email protected]"
required
type="email"
Expand All @@ -35,14 +42,15 @@ export default function Login() {
Forgot your password?
</Link>
</div>
<Input id="password" required type="password" />
<Input id="password" required type="password" name="password" />
</div>
<div className="flex items-center space-x-2">
<Checkbox id="remember" />
<Label className="text-sm" htmlFor="remember">
Remember me
</Label>
</div>
{state?.message && <p className="text-red-500">{state.message}</p>}
<Button className="w-full">Login</Button>
<Button className="w-full" variant="outline">
Login with Google
Expand Down
18 changes: 3 additions & 15 deletions app/dashboard/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
HomeIcon,
LineChartIcon,
LogOutIcon,
PackageIcon,
ShoppingCartIcon,
UsersIcon,
} from '@/components/ui/icons';
import LogoutButton from './logout-button';
import { PackageIcon } from '@/components/ui/icons';
import { Input } from '@/components/ui/input';
import Image from 'next/image';
import Link from 'next/link';
Expand Down Expand Up @@ -56,13 +50,7 @@ export default function Layout({
</nav>
</div>
<div className="border-t p-4 dark:border-gray-700">
<Link
className="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-gray-500 transition-all hover:text-gray-900 hover:dark:text-gray-300"
href="#"
>
<LogOutIcon className="h-4 w-4" />
Logout
</Link>
<LogoutButton />
</div>
</div>
</div>
Expand Down
17 changes: 17 additions & 0 deletions app/dashboard/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import { logout } from '@/lib/auth';
import { LogOutIcon } from '@/components/ui/icons';
export default function LogoutButton() {
return (
<button
className="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-gray-500 transition-all hover:text-gray-900 hover:dark:text-gray-300"
onClick={async () => {
await logout();
}}
>
<LogOutIcon className="h-4 w-4" />
Logout
</button>
);
}
42 changes: 37 additions & 5 deletions lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import {
LoginFormSchema,
SignupFormSchema,
} from '@/lib/definitions';
import { createSession } from '@/lib/session';
import { createSession, deleteSession } from '@/lib/session';
import bcrypt from 'bcrypt';
import { eq } from 'drizzle-orm';
import { redirect } from 'next/navigation';

export async function signup(state: FormState, formData: FormData) {
// 1. Validate form fields
Expand Down Expand Up @@ -57,7 +59,6 @@ export async function signup(state: FormState, formData: FormData) {
}
}

// TODO: Login and logout functionality
export async function login(state: FormState, formData: FormData) {
// 1. Validate form fields
const validatedFields = LoginFormSchema.safeParse({
Expand All @@ -66,12 +67,43 @@ export async function login(state: FormState, formData: FormData) {
});

// 2. If any form fields are invalid, return early and display errors
// 3. Query the database
if (!validatedFields.success) {
return {
message: validatedFields.error.flatten().fieldErrors,
};
}

// 3. Query the database for the user with the given email
const user = await db.query.users.findFirst({
where: eq(users.email, validatedFields.data.email),
});

// If user is not found, return an error
if (!user) {
return {
message: 'No user found with that email.',
};
}

// 4. Compare the user's password with the hashed password in the database
const passwordMatch = await bcrypt.compare(
validatedFields.data.password,
user.password,
);

// If the password does not match, return an error
if (!passwordMatch) {
return {
message: 'Invalid login credentials.',
};
}

// 5. If the password is correct, create a session for the user
await createSession(user.id);
}

export async function logout() {
// 1. Destroy the user's session
// 2. Redirect the user to the homepage
console.log('logging out');
deleteSession();
redirect('/login');
}

0 comments on commit d01cdfb

Please sign in to comment.