Role-based API, system notifications & intercepted routes improvements
leojuriolli 11 months ago
Yesterday I added roles to every user. The default role is user
, and the other one is admin
. To make it easier to manage on the codebase, I used Next Auth callbacks to add a boolean to the user session object called isAdmin
:
callbacks: {
session: async ({ session, user }) => {
session.user.id = user.id;
// new:
session.user.isAdmin = user.role === "admin";
return Promise.resolve(session);
},
},
New notifications
I also added system notifications to send alerts to users. There are four types of system notifications, and all of them are sent only when a new user signs in for the first time:
- Welcome notification.
- Call to action to create your first post.
- Suggest adding a profile picture if user does not have one.
- Suggest adding a username if empty.
For developing this I used Next Auth's newUser
page. This page is where Next Auth redirects a user when they sign in for the first time.
There, all we do is create the notifications, it shouldn't even be noticiable that there was a change of pages, before being redirected back to the default flow:
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getServerSession(context.req, context.res, authOptions);
const callbackUrl = context.query.callbackUrl as string;
if (!session?.user) {
return { redirect: { destination: "/" } };
}
// Only create welcome notifications once.
const userHasAlreadyBeenWelcomed = await prisma.notification.findFirst({
where: {
type: "WELCOME",
notifiedId: session?.user.id,
},
});
if (!userHasAlreadyBeenWelcomed) {
const welcomeNotification = prisma.notification.create({
data: {
type: "WELCOME" as const,
notifierId: session?.user.id,
notifiedId: session?.user.id,
},
});
const firstPostNotification = prisma.notification.create({
data: {
type: "FIRST-POST" as const,
notifierId: session?.user.id,
notifiedId: session?.user.id,
},
});
// fetching in parallel to reduce wait.
await Promise.all([welcomeNotification, firstPostNotification]);
}
return { redirect: { destination: callbackUrl || "/" } };
}
Intercepted routes improvements
Intercepted routes for posts were working, but when trying to navigate with the browser back/forward buttons, it wouldn't open the post. To fix this, I changed the approach:
Before, there was a <PostModal>
inside every card, and it would only open onClick
to the <Link>
. I changed it so there is only one <PostModal />
on the whole app, and it tracks when to be opened or closed based on the router state (query, current route, etc.)
Other changes include:
- Bugfixes
- All dates are formatted on the server-side now.
- Navigation sidebar links
isActive
state was being set tofalse
after opening a post modal.