After setting up the user authentication system, it is time for us to add a dashboard to out SaaS app. This dashboard should only be accessible to authenticated users, and it should provide them with options to update user information, such as the name and email address.
Updating the navbar
Let's start with the navbar, our navigation menu needs to be updated to show a Get Started button for unauthenticated users and a Dashboard button for authenticated users.
For unauthenticated users:
For authenticated users:
In order to achieve this, we need to retrieve the user session in our navbar component.
If the session
exists, user is authenticated, and the Dashboard button will be displayed.
If the session
does not exist, user is not authenticated, and the Get Started button will be displayed instead.
components/navbar.jsx
1import { auth } from "@/libs/auth";
2
3export default async function Navbar() {
4 const session = await auth();
5
6 return (
7 <nav className="flex items-center justify-between px-6 py-4 bg-white shadow-md">
8 <a href="/" className="text-xl font-bold">
9 MySaaS
10 </a>
11
12 <div className="hidden md:flex gap-6">
13 <a href="/features" className="hover:text-blue-600">
14 Features
15 </a>
16 <a href="/pricing" className="hover:text-blue-600">
17 Pricing
18 </a>
19 <a href="/about" className="hover:text-blue-600">
20 About
21 </a>
22 </div>
23
24 {session ? (
25 <a
26 href="/dashboard"
27 className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
28 Dashboard
29 </a>
30 ) : (
31 <a
32 href="/signin"
33 className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
34 Get Started
35 </a>
36 )}
37 </nav>
38 );
39}
Creating the dashboard layout
As for the dashboard itself, it can be designed in many different ways. As an example, we are going to have a side menu on the left side, allowing the user to navigate between different dashboard pages, which will be shown on the right side.
To implement this layout, we'll need to add layout.jsx
and page.jsx
files under app/dashboard/
.
1src/app
2├── api
3├── check-your-email
4├── dashboard
5│ ├── layout.jsx <===== Layout for the dashboard
6│ └── page.jsx <===== Dashboard homepage
7├── favicon.ico
8├── globals.css
9├── layout.jsx
10├── page.jsx
11├── pricing
12└── signin
Create a navigation menu inside the dashboard layout.jsx
. This ensures that the menu will be shared across all future dashboard pages we are going to create.
app/dashboard/layout.jsx
1import Link from "next/link";
2
3export default function DashboardLayout({ children }) {
4 return (
5 <div className="min-h-screen flex">
6 <div className="w-52 bg-gray-900 text-white">
7 <nav className="mt-6">
8 <ul className="space-y-2">
9 <li>
10 <Link
11 href="/dashboard"
12 className="block px-6 py-2 hover:bg-gray-700">
13 Home
14 </Link>
15 </li>
16 <li>
17 <Link
18 href="/dashboard/settings"
19 className="block px-6 py-2 hover:bg-gray-700">
20 Settings
21 </Link>
22 </li>
23 <li>
24 <Link
25 href="/dashboard/analytics"
26 className="block px-6 py-2 hover:bg-gray-700">
27 Analytics
28 </Link>
29 </li>
30 <li>
31 <Link
32 href="/dashboard/reports"
33 className="block px-6 py-2 hover:bg-gray-700">
34 Reports
35 </Link>
36 </li>
37 </ul>
38 </nav>
39 </div>
40
41 <div className="flex-1 bg-gray-100 p-6">{children}</div>
42 </div>
43 );
44}
app/dashboard/page.jsx
1import { auth } from "@/libs/auth";
2
3export default async function () {
4 const session = await auth();
5 return <div>Welcome, {session?.user?.name || session?.user?.email}!</div>;
6}
Blocking unauthenticated access
Creating the user settings page
app/dashboard/settings/page.jsx
1import { auth } from "@/libs/auth";
2import prisma from "@/libs/db";
3import { redirect } from "next/navigation";
4
5export default async function SettingsPage() {
6 const session = await auth();
7 return (
8 <div className="flex min-h-[80vh] items-center justify-center bg-gray-100">
9 <div className="w-full max-w-md bg-white p-8 rounded-lg shadow-md">
10 <h1 className="text-2xl font-bold text-center mb-6">User Settings</h1>
11 <form
12 action={async (formData) => {
13 "use server";
14 await prisma.user.update({
15 where: {
16 email: session?.user?.email,
17 },
18 data: {
19 name: formData.get("name"),
20 },
21 });
22
23 redirect("/dashboard/settings");
24 }}
25 className="space-y-6">
26 <div>
27 <label
28 htmlFor="name"
29 className="block text-sm font-medium text-gray-700">
30 Name
31 </label>
32 <input
33 type="text"
34 id="name"
35 name="name"
36 defaultValue={session?.user?.name || ""}
37 className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
38 required
39 />
40 </div>
41
42 <div>
43 <label
44 htmlFor="email"
45 className="block text-sm font-medium text-gray-700">
46 Email
47 </label>
48 <input
49 type="email"
50 id="email"
51 name="email"
52 defaultValue={session?.user?.email || ""}
53 className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
54 required
55 />
56 </div>
57
58 <div>
59 <button
60 type="submit"
61 className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
62 Update Profile
63 </button>
64 </div>
65 </form>
66 </div>
67 </div>
68 );
69}