Skip to content

Commit 5dd9632

Browse files
committed
evaluationcount context, spinner based on font size
1 parent e6f4bc5 commit 5dd9632

File tree

5 files changed

+67
-32
lines changed

5 files changed

+67
-32
lines changed

poliloom-gui/src/app/layout.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { SessionProvider } from '@/components/SessionProvider'
66
import { UserPreferencesProvider } from '@/contexts/UserPreferencesContext'
77
import { EvaluationSessionProvider } from '@/contexts/EvaluationSessionContext'
88
import { UserProgressProvider } from '@/contexts/UserProgressContext'
9+
import { EvaluationCountProvider } from '@/contexts/EvaluationCountContext'
910
import { FetchInterceptor } from '@/components/FetchInterceptor'
1011
import { MobileGuard } from '@/components/layout/MobileGuard'
1112
import { Header } from '@/components/layout/Header'
@@ -42,8 +43,12 @@ export default async function RootLayout({
4243
<UserPreferencesProvider>
4344
<EvaluationSessionProvider>
4445
<UserProgressProvider>
45-
<Header />
46-
<MobileGuard>{children}</MobileGuard>
46+
<EvaluationCountProvider>
47+
<MobileGuard>
48+
<Header />
49+
{children}
50+
</MobileGuard>
51+
</EvaluationCountProvider>
4752
</UserProgressProvider>
4853
</EvaluationSessionProvider>
4954
</UserPreferencesProvider>

poliloom-gui/src/app/stats/page.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ describe('Stats Page', () => {
106106

107107
await waitFor(() => {
108108
expect(screen.getByText('Evaluations Over Time')).toBeInTheDocument()
109-
expect(screen.getByText('Evaluation Coverage by Country')).toBeInTheDocument()
109+
expect(screen.getByText('Coverage by Country')).toBeInTheDocument()
110110
})
111111
})
112112

poliloom-gui/src/components/layout/Header.tsx

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,17 @@
11
'use client'
22

3-
import { useState, useEffect, useRef } from 'react'
3+
import { useState, useEffect } from 'react'
44
import { useSession, signOut, signIn } from 'next-auth/react'
55
import Image from 'next/image'
66
import Link from 'next/link'
77
import { Button } from '@/components/ui/Button'
88
import { SpinningCounter } from '@/components/ui/SpinningCounter'
9+
import { useEvaluationCount } from '@/contexts/EvaluationCountContext'
910

1011
export function Header() {
1112
const { status } = useSession()
1213
const [menuOpen, setMenuOpen] = useState(false)
13-
const [evaluationCount, setEvaluationCount] = useState<number | null>(null)
14-
15-
useEffect(() => {
16-
if (status !== 'authenticated') return
17-
18-
const fetchEvaluationCount = async () => {
19-
try {
20-
const response = await fetch('/api/stats/count')
21-
if (response.ok) {
22-
const data = await response.json()
23-
24-
setEvaluationCount(data.total)
25-
}
26-
} catch {
27-
// Silently fail - counter just won't show
28-
}
29-
}
30-
31-
fetchEvaluationCount()
32-
const interval = setInterval(fetchEvaluationCount, 2000)
33-
return () => clearInterval(interval)
34-
}, [status])
14+
const { evaluationCount } = useEvaluationCount()
3515

3616
useEffect(() => {
3717
if (!menuOpen) return

poliloom-gui/src/components/ui/SpinningCounter.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,26 @@ interface SpinningCounterProps {
77
title?: string
88
}
99

10-
const DIGIT_HEIGHT = 22
10+
// Height in em units - scales with font size
11+
const DIGIT_HEIGHT_EM = 1.8
1112

1213
function DigitWheel({ digit }: { digit: number }) {
1314
return (
1415
<div
15-
className="relative w-4 overflow-hidden bg-gray-50 border-x border-gray-100 first:border-l-0 first:rounded-l last:border-r-0 last:rounded-r"
16-
style={{ height: DIGIT_HEIGHT }}
16+
className="relative overflow-hidden bg-gray-50 border-x border-gray-100 first:border-l-0 first:rounded-l last:border-r-0 last:rounded-r"
17+
style={{ height: `${DIGIT_HEIGHT_EM}em`, width: '1.1em' }}
1718
>
1819
<div
1920
className="absolute w-full transition-transform duration-500 ease-out"
2021
style={{
21-
transform: `translateY(-${digit * DIGIT_HEIGHT}px)`,
22+
transform: `translateY(-${digit * DIGIT_HEIGHT_EM}em)`,
2223
}}
2324
>
2425
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((n) => (
2526
<div
2627
key={n}
27-
className="flex items-center justify-center text-gray-700 font-semibold text-sm leading-none tabular-nums"
28-
style={{ height: DIGIT_HEIGHT }}
28+
className="flex items-center justify-center text-gray-700 font-semibold leading-none tabular-nums"
29+
style={{ height: `${DIGIT_HEIGHT_EM}em` }}
2930
>
3031
{n}
3132
</div>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use client'
2+
3+
import React, { createContext, useContext, useState, useEffect } from 'react'
4+
import { useSession } from 'next-auth/react'
5+
6+
interface EvaluationCountContextType {
7+
evaluationCount: number | null
8+
}
9+
10+
const EvaluationCountContext = createContext<EvaluationCountContextType | undefined>(undefined)
11+
12+
export function EvaluationCountProvider({ children }: { children: React.ReactNode }) {
13+
const { status } = useSession()
14+
const [evaluationCount, setEvaluationCount] = useState<number | null>(null)
15+
16+
useEffect(() => {
17+
if (status !== 'authenticated') return
18+
19+
const fetchEvaluationCount = async () => {
20+
try {
21+
const response = await fetch('/api/stats/count')
22+
if (response.ok) {
23+
const data = await response.json()
24+
setEvaluationCount(data.total)
25+
}
26+
} catch {
27+
// Silently fail
28+
}
29+
}
30+
31+
fetchEvaluationCount()
32+
const interval = setInterval(fetchEvaluationCount, 2000)
33+
return () => clearInterval(interval)
34+
}, [status])
35+
36+
return (
37+
<EvaluationCountContext.Provider value={{ evaluationCount }}>
38+
{children}
39+
</EvaluationCountContext.Provider>
40+
)
41+
}
42+
43+
export function useEvaluationCount() {
44+
const context = useContext(EvaluationCountContext)
45+
if (context === undefined) {
46+
throw new Error('useEvaluationCount must be used within an EvaluationCountProvider')
47+
}
48+
return context
49+
}

0 commit comments

Comments
 (0)