Static Export Navigation Fix
This document explains the fixes made to address navigation and authentication issues in the static export version of the Help Desk application.
Issues Fixed
-
Ticket Detail Navigation Issue:
- Problem: When clicking on a ticket from All Tickets view, the auth screen appeared briefly before redirecting to the Create Ticket screen.
- Root cause: Authentication check in middleware was redirecting to the wrong page, and the navigation method was not maintaining auth state properly.
- Solution: Implemented destination preservation through the authentication flow to ensure users reach their intended page.
-
Notification Navigation Issue:
- Problem: When clicking on a notification, navigation to the ticket detail page was unreliable.
- Fixed by using direct window.location.href navigation instead of Next.js router.push().
-
Authentication Flow Improvement:
- Problem: After sign-in, users were always redirected to /tickets/new instead of their intended destination.
- Solution: Added destination parameter tracking through the entire auth flow.
Technical Details
1. Middleware Improvements
The middleware (src/middleware.ts) has been updated to:
- Add special handling for ticket detail pages with a regex pattern match
- Improve logging for better debugging
- Fix the redirection logic to avoid looping redirects
- Change the default redirect destination from
/tickets/newto/ticketsfor authenticated users
// Special handling for ticket detail pagesconst isTicketDetailPage = /^\/tickets\/[^/]+$/.test(path) && path !== '/tickets/new' && path !== '/tickets/all';if (isTicketDetailPage) { // For ticket detail pages, just check authentication but don't redirect to dashboard if (!isAuthenticated) { return NextResponse.redirect(new URL('/auth/signin', request.url)); } return NextResponse.next();}2. TicketDetail Component Auth Check
To fix the build error with static generation, we moved the authentication logic from the page component to the TicketDetail component:
The ticket detail component (src/components/tickets/TicketDetail.tsx) has been updated to:
- Include explicit authentication check with proper loading states
- Handle redirection to sign-in with destination preservation
- Show appropriate loading and error messages
- Add extensive logging for debugging
const checkAuthAndFetchTicket = async () => { // Wait for auth to complete before checking if (loading) { console.log('Authentication still loading, waiting...'); return; }
// Handle unauthenticated users if (!user) { console.log('No authenticated user, redirecting to sign-in'); setError('You must be logged in to view this ticket.');
// Store current URL as the destination for post-login redirect const currentPath = window.location.pathname; const destination = encodeURIComponent(currentPath); window.location.href = `/auth/signin?destination=${destination}`; return; }
// Fetch ticket logic...};The page component (src/app/(app)/tickets/[id]/page.tsx) remains a simple server component that supports static generation:
export async function generateStaticParams() { return [{ id: 'placeholder' }];}
export default function TicketPage({ params }: TicketPageProps) { return <TicketDetail ticketId={params.id} />;}This approach satisfies the Next.js static export requirement that files with generateStaticParams() cannot use ‘use client’ directive.
3. Enhanced Navigation Approach
All ticket navigation has been updated to use native HTML anchors with programmatic clicks, which is more reliable than both router.push() and direct window.location changes:
- In TicketList.tsx:
onClick={(e) => { e.preventDefault(); console.log(`Navigating to ticket from title: ${ticket.id}`);
// Use a regular link for most reliable navigation const link = document.createElement('a'); link.href = `/tickets/${ticket.id}`; link.setAttribute('data-ticket-id', ticket.id); link.setAttribute('data-navigation-type', 'ticket-title'); document.body.appendChild(link); link.click(); document.body.removeChild(link);}}- In Navbar.tsx (for notifications):
onClick={() => { console.log('Navigating to ticket from notifications:', lastTicket.id); handleCloseNotifications();
// Use a regular link for most reliable navigation const link = document.createElement('a'); link.href = `/tickets/${lastTicket.id}`; link.setAttribute('data-ticket-id', lastTicket.id); link.setAttribute('data-navigation-type', 'notification'); document.body.appendChild(link); link.click(); document.body.removeChild(link);}}This approach ensures:
- Fresh page load with proper authentication check
- No stale state between page navigations
- Consistent behavior in static exports
4. Destination Preservation
Added a system to preserve the intended destination across the authentication flow:
- In middleware (when redirecting to sign-in):
// Store current path as destinationconst signinUrl = new URL('/auth/signin', request.url);if (isTicketDetailPage) { signinUrl.searchParams.set('destination', path);}return NextResponse.redirect(signinUrl);- In SignInPage.tsx (reading the destination):
// Extract destination from URL parametersuseEffect(() => { if (typeof window !== 'undefined') { const params = new URLSearchParams(window.location.search); const dest = params.get('destination'); if (dest) { setDestination(dest); } }}, []);- In authentication-related redirects:
if (destination && destination.startsWith('/tickets/')) { window.location.href = destination;} else { window.location.href = '/tickets';}This ensures that users reach their intended destination after authentication.
Authentication Flow in Static Export
The authentication flow now works as follows:
- User clicks a ticket from the list or notification
- Direct page navigation triggers a full page reload
- Middleware checks for authentication
- Page component performs a secondary check for auth state
- When authenticated, the ticket detail component loads
Testing the Fix
To verify the fix:
- Log in as admin user
- Go to “All Tickets” page
- Click on any ticket
- You should see the ticket details page load correctly without being redirected to create ticket
- Try the same flow with notifications by clicking on a notification in the bell dropdown
If at any point you get redirected to the login page, check the console logs to see what’s happening with the authentication state.
Additional Debugging
Added extensive debugging logs to the TicketDetail component:
// Log current state and auth statusconsole.log(`TicketDetail: Auth loading: ${loading}, User:`, user ? user.uid : 'none', 'Role:', userData?.role);console.log(`TicketID being viewed: ${ticketId}, Is placeholder:`, ticketId === 'placeholder');
// Add additional debugging for network requestsconsole.log(`Making Firestore request for document: tickets/${ticketId}`);
// Log ticket data on successful fetchconsole.log('Ticket loaded successfully:', { id: fetchedTicket.id, title: fetchedTicket.title, status: fetchedTicket.status, participants: fetchedTicket.participants.length});
// Log access control checksconsole.log('Access check:', { isParticipant, userRole: userData?.role, isAdmin: isAdmin});Further Improvements
For even better static export support, consider:
- Adding a service worker for improved caching
- Using localStorage for temporary ticket caching to improve loading experience
- Implementing optimistic UI updates for notifications
- Adding network state monitoring for more reliable Firestore access
- Creating a fallback mechanism that shows cached ticket data when offline