@@ -70,18 +70,14 @@ export default function ReviewQueuePage() {
7070
7171function ReviewQueuePageInner ( ) {
7272 const { data : session } = useSession ( ) ;
73- const { isReviewer, isModerator } = useUserRoles ( ) ;
73+ const { isReviewer, isModerator, isLoading : rolesLoading } = useUserRoles ( ) ;
7474 const router = useRouter ( ) ;
7575 const pathname = usePathname ( ) ;
7676 const searchParams = useSearchParams ( ) ;
7777 const API_BASE = useMemo ( ( ) => getPublicApiUrl ( ) , [ ] ) ;
7878 const [ contributions , setContributions ] = useState < Contribution [ ] > ( [ ] ) ;
7979 const [ isLoading , setIsLoading ] = useState ( true ) ;
8080 const [ error , setError ] = useState < string | null > ( null ) ;
81-
82- if ( ! isReviewer ) {
83- return < AccessDenied requiredRole = "reviewer" userEmail = { session ?. user ?. email } /> ;
84- }
8581 const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
8682 const [ totalPages , setTotalPages ] = useState ( 1 ) ;
8783 const [ totalCount , setTotalCount ] = useState ( 0 ) ;
@@ -110,6 +106,7 @@ function ReviewQueuePageInner() {
110106 [ pathname , router , searchParams ] ,
111107 ) ;
112108
109+ // Hooks must run unconditionally — gate rendering after all hooks below.
113110 useEffect ( ( ) => {
114111 const qt = ( searchParams . get ( 'queue_type' ) || 'all' ) as QueueTab ;
115112 if ( [ 'all' , 'new_claims' , 'conflicts' , 'flagged' , 'expiring' ] . includes ( qt ) ) setActiveTab ( qt ) ;
@@ -189,10 +186,10 @@ function ReviewQueuePageInner() {
189186 } , [ API_BASE , contradictionsOnly , getHeaders , minWorstSourceRank , myDomainOnly , ordering , staleDays ] ) ;
190187
191188 useEffect ( ( ) => {
192- if ( ! session ) return ;
189+ if ( ! session || ! isReviewer ) return ;
193190 fetchContributions ( currentPage , activeTab , selectedCategory , appliedSearch ) ;
194191 fetchQueueCounts ( ) ;
195- } , [ session , currentPage , activeTab , selectedCategory , appliedSearch , ordering , staleDays , contradictionsOnly , minWorstSourceRank , myDomainOnly , fetchContributions , fetchQueueCounts ] ) ;
192+ } , [ session , isReviewer , currentPage , activeTab , selectedCategory , appliedSearch , ordering , staleDays , contradictionsOnly , minWorstSourceRank , myDomainOnly , fetchContributions , fetchQueueCounts ] ) ;
196193
197194 const handleTabChange = ( tab : string ) => {
198195 setActiveTab ( tab as QueueTab ) ; setCurrentPage ( 1 ) ;
@@ -256,6 +253,15 @@ function ReviewQueuePageInner() {
256253 const formatUserName = ( u : UserInfo ) => `${ u . first_name } ${ u . last_name } ` . trim ( ) || u . username ;
257254 const getRevisionInfo = ( c : Contribution ) => c . latest_revision ? `Rev. ${ c . latest_revision . revision_number } ` : '—' ;
258255
256+ if ( rolesLoading ) {
257+ return (
258+ < div className = "p-8 text-center text-muted-foreground" > Checking reviewer access…</ div >
259+ ) ;
260+ }
261+ if ( ! isReviewer ) {
262+ return < AccessDenied requiredRole = "reviewer" userEmail = { session ?. user ?. email } /> ;
263+ }
264+
259265 return (
260266 < TooltipProvider >
261267
@@ -273,7 +279,18 @@ function ReviewQueuePageInner() {
273279 < h1 className = "text-3xl font-black text-white" >
274280 Review < span className = "text-white/90" > Queue</ span >
275281 </ h1 >
276- < p className = "text-blue-100 max-w-lg" > Evaluate claims, resolve conflicts, maintain provenance</ p >
282+ < p className = "text-blue-100 max-w-lg" >
283+ Evaluate claims, resolve conflicts, maintain provenance. Prefer this queue for
284+ source-tier triage — use{ " " }
285+ < button
286+ type = "button"
287+ className = "underline underline-offset-2 hover:text-white"
288+ onClick = { ( ) => router . push ( "/curation/contributions" ) }
289+ >
290+ Curation Queues
291+ </ button > { " " }
292+ only for quick bulk accept/reject.
293+ </ p >
277294 </ div >
278295 < div className = "flex gap-2 flex-wrap" >
279296 < Button onClick = { ( ) => router . push ( '/curation/dashboard' ) } variant = "outline" className = "border-white/30 text-white hover:bg-white/20" > Dashboard</ Button >
0 commit comments