Observer platform: mobile fixes, data/UX overhaul, animated nav
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m41s
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m41s
- Fix dashboard default round selection to target active round instead of R1 - Move edition selector from dashboard header to hamburger menu via shared context - Add observer-friendly status labels (Not Reviewed / Under Review / Reviewed) - Fix pipeline completion: closed rounds show 100%, cap all rates at 100% - Round badge on projects list shows furthest round reached - Hide scores/evals for projects with zero evaluations - Enhance project detail round history with pass/reject indicators from ProjectRoundState - Remove irrelevant fields (Org Type, Budget, Duration) from project detail - Clickable juror workload with expandable project assignments - Humanize activity feed with icons and readable messages - Fix jurors table: responsive card layout on mobile - Fix criteria chart: horizontal bars for readable labels on mobile - Animate hamburger menu open/close with CSS grid transition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
67
src/components/observer/observer-edition-context.tsx
Normal file
67
src/components/observer/observer-edition-context.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
'use client'
|
||||
|
||||
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react'
|
||||
import { trpc } from '@/lib/trpc/client'
|
||||
|
||||
type Program = {
|
||||
id: string
|
||||
name: string | null
|
||||
year?: number
|
||||
rounds?: Array<{ id: string; name: string; status: string; competitionId?: string }>
|
||||
}
|
||||
|
||||
type EditionContextValue = {
|
||||
programs: Program[]
|
||||
selectedProgramId: string
|
||||
setSelectedProgramId: (id: string) => void
|
||||
activeRoundId: string
|
||||
}
|
||||
|
||||
const EditionContext = createContext<EditionContextValue | null>(null)
|
||||
|
||||
export function useEditionContext() {
|
||||
const ctx = useContext(EditionContext)
|
||||
if (!ctx) throw new Error('useEditionContext must be used within EditionProvider')
|
||||
return ctx
|
||||
}
|
||||
|
||||
function findBestRound(rounds: Array<{ id: string; status: string }>): string {
|
||||
const active = rounds.find(r => r.status === 'ROUND_ACTIVE')
|
||||
if (active) return active.id
|
||||
const closed = [...rounds].filter(r => r.status === 'ROUND_CLOSED').pop()
|
||||
if (closed) return closed.id
|
||||
return rounds[0]?.id ?? ''
|
||||
}
|
||||
|
||||
export function EditionProvider({ children }: { children: ReactNode }) {
|
||||
const [selectedProgramId, setSelectedProgramId] = useState<string>('')
|
||||
|
||||
const { data: programs } = trpc.program.list.useQuery(
|
||||
{ includeStages: true },
|
||||
{ refetchInterval: 30_000 },
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (programs && programs.length > 0 && !selectedProgramId) {
|
||||
setSelectedProgramId(programs[0].id)
|
||||
}
|
||||
}, [programs, selectedProgramId])
|
||||
|
||||
const typedPrograms = (programs ?? []) as Program[]
|
||||
const selectedProgram = typedPrograms.find(p => p.id === selectedProgramId)
|
||||
const rounds = (selectedProgram?.rounds ?? []) as Array<{ id: string; status: string }>
|
||||
const activeRoundId = findBestRound(rounds)
|
||||
|
||||
return (
|
||||
<EditionContext.Provider
|
||||
value={{
|
||||
programs: typedPrograms,
|
||||
selectedProgramId,
|
||||
setSelectedProgramId,
|
||||
activeRoundId,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</EditionContext.Provider>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user