Add bilingual i18n UI and lighten component shadows

This commit is contained in:
Bernard Ngandu
2025-10-10 10:30:28 +02:00
parent 8f4b954af8
commit 0422becdd0
20 changed files with 622 additions and 141 deletions
+27 -10
View File
@@ -16,9 +16,14 @@ interface SubmitResult {
success: boolean
}
export interface FeedError {
key: string
values?: Record<string, unknown>
}
export function useHotspotFeed({ autoRefreshMs = DEFAULT_REFRESH_MS }: UseHotspotFeedOptions = {}) {
const [status, setStatus] = useState<FeedStatus>('loading')
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const [error, setError] = useState<FeedError | null>(null)
const [rawPoints, setRawPoints] = useState<ApiPoint[]>([])
const [rawDensity, setRawDensity] = useState<ApiDensityCell[]>([])
const [rawLatestByUser, setRawLatestByUser] = useState<ApiPoint[]>([])
@@ -50,7 +55,7 @@ export function useHotspotFeed({ autoRefreshMs = DEFAULT_REFRESH_MS }: UseHotspo
try {
const response = await fetch(`${API_BASE}?limit=${SNAPSHOT_LIMIT}`, { cache: 'no-store' })
if (!response.ok) {
throw new Error('Unable to reach the hotspot feed.')
throw new Error('feed-unavailable')
}
const data: ApiSnapshot = await response.json()
@@ -59,14 +64,15 @@ export function useHotspotFeed({ autoRefreshMs = DEFAULT_REFRESH_MS }: UseHotspo
setRawLatestByUser(data.latestByUser ?? [])
setClientKey(data.clientKey ?? null)
setLastUpdated(data.updatedAt ?? new Date().toISOString())
setErrorMessage(null)
setError(null)
initialLoadRef.current = false
const nextStatus = previousStatus === 'posting' ? 'posting' : 'idle'
setStatusSafe(nextStatus)
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error while loading hotspots.'
setErrorMessage(message)
const message = error instanceof Error ? error.message : null
const key = message === 'feed-unavailable' ? 'errors.feedUnavailable' : 'errors.feedUnknown'
setError({ key })
if (initialLoadRef.current) {
setStatusSafe('error')
} else if (previousStatus !== 'posting') {
@@ -104,16 +110,27 @@ export function useHotspotFeed({ autoRefreshMs = DEFAULT_REFRESH_MS }: UseHotspo
if (!response.ok) {
const payload = await response.json().catch(() => null)
const message = payload?.message ?? 'Unable to store your signal.'
throw new Error(message)
const message = payload?.message as string | undefined
if (message) {
setError({ key: 'errors.submitWithReason', values: { message } })
} else {
setError({ key: 'errors.submitUnavailable' })
}
setStatusSafe('error')
return { success: false }
}
await fetchSnapshot({ silent: true })
setError(null)
setStatusSafe('idle')
return { success: true }
} catch (error) {
const message = error instanceof Error ? error.message : 'Something went wrong while saving your signal.'
setErrorMessage(message)
const message = error instanceof Error ? error.message : null
if (message) {
setError({ key: 'errors.submitWithReason', values: { message } })
} else {
setError({ key: 'errors.submitUnknown' })
}
setStatusSafe('error')
return { success: false }
}
@@ -157,7 +174,7 @@ export function useHotspotFeed({ autoRefreshMs = DEFAULT_REFRESH_MS }: UseHotspo
return {
status,
errorMessage,
error,
submitPoint,
fetchSnapshot,
rawDensity,