
Update - Haven's Heroes
Diane Larsen / March 4, 2025
Haven’s Heroes Development Update - March 2025
🚀 Progress, Fixes, and Lessons Learned
📌 Summary
Over the past few weeks, I’ve been making significant improvements to Haven’s Heroes, including fixing authentication issues, improving file uploads, refining role-based access, handling dark mode properly, and streamlining database interactions.
This update highlights the major fixes, enhancements, and lessons learned in building the project.
🔐 Authentication & User Role Fixes
1️⃣ Clerk Authentication Fixes
🔹 Issue:
userId
was sometimesundefined
, causing authentication failures.- Users were not being automatically redirected to the sign-in page when their session expired.
🔹 Solution:
- Used
getAuth(headers())
instead ofauth()
to properly retrieve the authenticated user. - Implemented instant redirection to
/sign-in
ifuserId
was missing. - Added a loading state to prevent UI flickers while Clerk was resolving authentication.
🔹 Code Fix:
useEffect(() => {
if (isLoaded && !userId) {
console.error("❌ User not authenticated! Redirecting to sign-in...");
router.push("/sign-in");
}
}, [isLoaded, userId, router]);
✅ Outcome: Seamless authentication handling with auto-redirects when needed.
2️⃣ Role-Based Access Control (RBAC) for Admins
🔹 Issue:
- Needed a way to restrict admin-only pages while keeping the user role data efficient.
- Prisma’s check constraints caused issues when adding a
role
column to theUser
model.
🔹 Solution:
- Added a
role
field to theUser
table with values"Admin"
and"Member"
, defaulting to"Member"
. - Implemented role-based access restrictions on
/admin
:- Non-admin users are redirected to the homepage instead of seeing an error.
- Used
select: { role: true }
in Prisma to fetch only the necessary field for efficiency.
🔹 Code Fix (Prisma Model Update):
model User {
id String @id @default(uuid())
username String @unique
role String @default("Member") // Admin or Member
}
🔹 Code Fix (Server Role Check):
import { getUserRole } from "@/lib/actions";
import Admin from "@/components/Admin";
const AdminPage = async () => {
const role = await getUserRole(); // ✅ Fetch role on the server
return <Admin role={role} />;
};
export default AdminPage;
✅ Outcome: Admin-only pages are now properly restricted and load efficiently.
📆 Birthday Tracking Enhancements
3️⃣ Improved Upcoming Birthdays Display
🔹 Issue:
- Birthdays Component (
Birthdays.tsx
) was fetching unnecessary data, causing performance issues. - Users without a birthday were still being included in the list.
🔹 Solution:
- Filtered users without a birthday so they don’t appear in the upcoming birthdays list.
- Added a “Members Missing Birthdays” section (only visible to admins).
- Clicking a user’s name now navigates to their profile page.
🔹 Code Fix (Fetching Upcoming Birthdays):
const upcomingBirthdays = await getUpcomingBirthdays(limit);
const usersMissingBirthdays = isAdmin ? await getUsersMissingBirthdays() : [];
✅ Outcome:
- Only users with birthdays are shown.
- Admins can track users missing birthdays.
- Improved UI performance by reducing unnecessary fetch requests.
🖼 Cloudinary File Upload Fixes
4️⃣ Instant Cover Image Updates
🔹 Issue:
CldUploadWidget
was causing TypeScript errors due to mismatched types.- Cover image wasn’t updating instantly after upload.
🔹 Solution:
- Checked if
result.info
was an object before accessingsecure_url
. - Updated the cover image preview instantly after upload.
- Displayed a warning message: "Cover image updated! Changes will not be saved until you press 'Update'."
🔹 Code Fix:
<CldUploadWidget
uploadPreset="havens_heroes"
onSuccess={(result)=> {
if (typeof result.info= "object" && result.info = null && "secure_url" in result.info) {
setCover(result.info.secure_url as string);
setShowWarning(true);
}
}}
>
✅ Outcome: Cover image updates instantly, and users get a warning if changes aren't saved.
🌙 Dark Mode Enhancements
5️⃣ Fixed Dark Mode UI Issues
🔹 Issue:
- The modal background remained white even in dark mode.
🔹 Solution:
- Explicitly set dark mode styles using Tailwind’s
dark:
classes. - Verified
ThemeProvider
was properly configured.
🔹 Code Fix:
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<form className="bg-white dark:bg-gray-900 dark:text-white p-12 rounded-lg shadow-md">
✅ Outcome: UI elements now properly reflect system dark mode settings.
🔧 Middleware & Database Optimizations
6️⃣ Improved Middleware Database Handling
🔹 Issue:
- Database checks were being called multiple times, causing unnecessary fetch requests.
- Intermittent Supabase connection failures led to inconsistent app behavior.
🔹 Solution:
- Added a global variable (
dbConnected
) to track database connection status. - Prevented redundant checks by storing the status in middleware.
- Redirected users to a maintenance page if the database was down.
🔹 Code Fix (Middleware Update):
declare global {
var dbConnected: boolean | undefined;
}
globalThis.dbConnected = globalThis.dbConnected ?? false;
export default clerkMiddleware(async (auth, req: NextRequest) => {
if (globalThis.dbConnected) {
console.log("✅ Database already verified");
return NextResponse.next();
}
try {
const res = await fetch(`${req.nextUrl.origin}/api/check-db`, {
method: "GET",
cache: "no-store",
});
if (!res.ok) {
return NextResponse.redirect(new URL("/maintenance", req.url));
}
globalThis.dbConnected = true;
} catch (error) {
console.error("❌ Database check failed:", error);
return NextResponse.redirect(new URL("/maintenance", req.url));
}
return NextResponse.next();
});
✅ Outcome:
- Database connections are checked only once per request cycle.
- Reduced unnecessary API calls and improved performance.
🚀 Final Outcome & Next Steps
✅ Fixed authentication issues (auto-redirect on session expiration).
✅ Admin role-based access now works properly.
✅ Birthday tracking is more efficient and only shows valid users.
✅ Dark mode styling is now fully functional.
✅ Cover image uploads instantly, with a warning message.
✅ Middleware now prevents excessive database checks.
🔜 What’s Next?
- Test Brevo email sending once the account is activated.
- Refine admin panel UI for better user management.
- Further optimize database queries to ensure scalability.
🚀 The platform is shaping up well! Looking forward to the next set of improvements. 🎉