From 8d6f3ca11f206541e77b5ea2b4088ec0cc4fbe7a Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 5 Mar 2026 14:23:27 +0100 Subject: [PATCH] fix: dashboard flickering + clickable logo change for applicants - Fix session auto-refresh causing re-render cascade by using useRef instead of useState and delaying the refresh by 3s - Make project logo clickable on dashboard and team page for team leads with hover pencil overlay and ProjectLogoUpload dialog Co-Authored-By: Claude Opus 4.6 --- src/app/(applicant)/applicant/page.tsx | 41 +++++++++++++++++---- src/app/(applicant)/applicant/team/page.tsx | 39 ++++++++++++++++---- src/components/layouts/role-nav.tsx | 13 +++++-- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/app/(applicant)/applicant/page.tsx b/src/app/(applicant)/applicant/page.tsx index 654e2b0..1f55990 100644 --- a/src/app/(applicant)/applicant/page.tsx +++ b/src/app/(applicant)/applicant/page.tsx @@ -18,6 +18,7 @@ import { CompetitionTimelineSidebar } from '@/components/applicant/competition-t import { WithdrawButton } from '@/components/applicant/withdraw-button' import { MentoringRequestCard } from '@/components/applicant/mentoring-request-card' import { AnimatedCard } from '@/components/shared/animated-container' +import { ProjectLogoUpload } from '@/components/shared/project-logo-upload' import { FileText, Calendar, @@ -29,6 +30,7 @@ import { ArrowRight, Star, AlertCircle, + Pencil, } from 'lucide-react' const statusColors: Record = { @@ -45,6 +47,7 @@ const statusColors: Record
- {/* Project logo */} -
- {data.logoUrl ? ( - {project.title} - ) : ( - - )} -
+ {/* Project logo — clickable for team leads to change */} + {project.isTeamLead ? ( + utils.applicant.getMyDashboard.invalidate()} + > + + + ) : ( +
+ {data.logoUrl ? ( + {project.title} + ) : ( + + )} +
+ )}

{project.title}

diff --git a/src/app/(applicant)/applicant/team/page.tsx b/src/app/(applicant)/applicant/team/page.tsx index dd0255f..3c99903 100644 --- a/src/app/(applicant)/applicant/team/page.tsx +++ b/src/app/(applicant)/applicant/team/page.tsx @@ -68,6 +68,7 @@ import { GraduationCap, Heart, Calendar, + Pencil, } from 'lucide-react' import { formatDateOnly } from '@/lib/utils' @@ -243,14 +244,36 @@ export default function ApplicantProjectPage() {
{/* Header */}
- {/* Project logo */} -
- {logoUrl ? ( - {project.title} - ) : ( - - )} -
+ {/* Project logo — clickable for team leads */} + {isTeamLead ? ( + refetchLogo()} + > + + + ) : ( +
+ {logoUrl ? ( + {project.title} + ) : ( + + )} +
+ )}

{project.title} diff --git a/src/components/layouts/role-nav.tsx b/src/components/layouts/role-nav.tsx index 0e973d2..6db07b6 100644 --- a/src/components/layouts/role-nav.tsx +++ b/src/components/layouts/role-nav.tsx @@ -1,6 +1,6 @@ 'use client' -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import Link from 'next/link' import { usePathname } from 'next/navigation' import { signOut, useSession } from 'next-auth/react' @@ -96,10 +96,15 @@ export function RoleNav({ navigation, roleName, user, basePath, statusBadge, edi signOut({ callbackUrl: '/login' }) } - // Auto-refresh session on mount to pick up role changes without requiring re-login + // Auto-refresh session once on initial mount to pick up role changes. + // Uses a ref (not state) to avoid triggering an extra re-render. + const sessionRefreshedRef = useRef(false) useEffect(() => { - if (isAuthenticated) { - updateSession() + if (isAuthenticated && !sessionRefreshedRef.current) { + sessionRefreshedRef.current = true + // Delay so the initial render finishes cleanly before session refresh + const timer = setTimeout(() => updateSession(), 3000) + return () => clearTimeout(timer) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isAuthenticated])