Skip to content

Commit

Permalink
Merge pull request #26 from RicardoGEsteves/settings-page
Browse files Browse the repository at this point in the history
feat: ✨ feat(settings-page): Update UI components and add settings page
  • Loading branch information
RicardoGEsteves authored Jan 14, 2024
2 parents b1d677e + 5d1678b commit 3326cd2
Show file tree
Hide file tree
Showing 12 changed files with 924 additions and 34 deletions.
82 changes: 82 additions & 0 deletions actions/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use server";

import * as z from "zod";
import bcrypt from "bcryptjs";

import { update } from "@/auth";
import { db } from "@/lib/db";
import { SettingsSchema } from "@/schemas";
import { getUserByEmail, getUserById } from "@/data/user";
import { currentUser } from "@/lib/auth";
import { generateVerificationToken } from "@/lib/tokens";
import { sendVerificationEmail } from "@/lib/mail";

export const settings = async (values: z.infer<typeof SettingsSchema>) => {
const user = await currentUser();

if (!user) {
return { error: "Unauthorized" };
}

const dbUser = await getUserById(user.id);

if (!dbUser) {
return { error: "Unauthorized" };
}

if (user.isOAuth) {
values.email = undefined;
values.password = undefined;
values.newPassword = undefined;
values.isTwoFactorEnabled = undefined;
}

if (values.email && values.email !== user.email) {
const existingUser = await getUserByEmail(values.email);

if (existingUser && existingUser.id !== user.id) {
return { error: "Email already in use!" };
}

const verificationToken = await generateVerificationToken(values.email);
await sendVerificationEmail(
verificationToken.email,
verificationToken.token
);

return { success: "Verification email sent!" };
}

if (values.password && values.newPassword && dbUser.password) {
const passwordsMatch = await bcrypt.compare(
values.password,
dbUser.password
);

if (!passwordsMatch) {
return { error: "Incorrect password!" };
}

const hashedPassword = await bcrypt.hash(values.newPassword, 10);
values.password = hashedPassword;
values.newPassword = undefined;
}

const updatedUser = await db.user.update({
where: { id: dbUser.id },
data: {
...values,
},
});

update({
user: {
name: updatedUser.name,
email: updatedUser.email,
isTwoFactorEnabled: updatedUser.isTwoFactorEnabled,
role: updatedUser.role,
},
});

return { success: "Settings Updated!" };
};
66 changes: 50 additions & 16 deletions app/(protected)/_components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,65 @@

import { usePathname } from "next/navigation";
import Link from "next/link";
import { MdMenu } from "react-icons/md";

import { NAV_LINKS } from "../_constants";
import { Button } from "@/components/ui/button";
import UserButton from "@/components/auth/user-button";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";

const Navbar = () => {
const pathName = usePathname();

return (
// TODO: Mobile navbar
<nav className="w-full fixed bg-secondary flex justify-between items-center p-4">
<div className="flex gap-x-2">
{NAV_LINKS.map((link, index) => (
<Button
key={index}
asChild
variant={pathName === link.path ? "default" : "outline"}
className="w-full hover:bg-sky-400 hover:text-primary-foreground"
>
<Link href={link.path}>{link.title}</Link>
</Button>
))}
</div>
<UserButton />
</nav>
<>
<nav className="hidden lg:flex w-full fixed top-0 h-14 bg-secondary justify-between items-center p-4">
<div className="flex gap-x-2">
{NAV_LINKS.map((link, index) => (
<Button
key={index}
asChild
variant={pathName === link.path ? "default" : "outline"}
className="w-full hover:bg-sky-400 hover:text-primary-foreground"
>
<Link href={link.path}>{link.title}</Link>
</Button>
))}
</div>
<UserButton />
</nav>

<nav className="flex bg-secondary items-center justify-between p-4 lg:hidden">
<Sheet>
<SheetTrigger>
<Button
asChild
variant="secondary"
size="sm"
className="w-full text-background hover:text-sky-400"
>
<MdMenu />
</Button>
</SheetTrigger>
<SheetContent>
<div className="flex-col p-2">
{NAV_LINKS.map((link, index) => (
<Button
key={index}
asChild
variant={pathName === link.path ? "default" : "outline"}
className="w-full hover:bg-sky-400 my-2 hover:text-primary-foreground"
>
<Link href={link.path}>{link.title}</Link>
</Button>
))}
</div>
</SheetContent>
</Sheet>

<UserButton />
</nav>
</>
);
};
export default Navbar;
9 changes: 4 additions & 5 deletions app/(protected)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ export default async function ProtectedLayout({

return (
<SessionProvider session={session}>
<div className="h-full w-full flex">
<Navbar />
<div className="w-full flex items-center justify-center mx-5">
{children}
</div>
<Navbar />

<div className="flex items-center justify-center mx-4 my-6 lg:mt-20">
{children}
</div>
</SessionProvider>
);
Expand Down
Loading

0 comments on commit 3326cd2

Please sign in to comment.