mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
feat(web): configure session preview limit (#629)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
DEFAULT_SESSION_PREVIEW_LIMIT,
|
||||
MAX_SESSION_PREVIEW_LIMIT,
|
||||
MIN_SESSION_PREVIEW_LIMIT,
|
||||
getInitialSessionPreviewLimit,
|
||||
normalizeSessionPreviewLimit,
|
||||
} from './useSessionPreviewLimit'
|
||||
|
||||
describe('useSessionPreviewLimit helpers', () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear()
|
||||
})
|
||||
|
||||
it('falls back to the default for missing or invalid values', () => {
|
||||
expect(getInitialSessionPreviewLimit()).toBe(DEFAULT_SESSION_PREVIEW_LIMIT)
|
||||
|
||||
window.localStorage.setItem('hapi-session-preview-limit', 'invalid')
|
||||
expect(getInitialSessionPreviewLimit()).toBe(DEFAULT_SESSION_PREVIEW_LIMIT)
|
||||
|
||||
window.localStorage.setItem('hapi-session-preview-limit', '12.5')
|
||||
expect(getInitialSessionPreviewLimit()).toBe(DEFAULT_SESSION_PREVIEW_LIMIT)
|
||||
})
|
||||
|
||||
it('reads valid stored values', () => {
|
||||
window.localStorage.setItem('hapi-session-preview-limit', '12')
|
||||
|
||||
expect(getInitialSessionPreviewLimit()).toBe(12)
|
||||
})
|
||||
|
||||
it('clamps values to the supported range', () => {
|
||||
expect(normalizeSessionPreviewLimit(0)).toBe(MIN_SESSION_PREVIEW_LIMIT)
|
||||
expect(normalizeSessionPreviewLimit(120)).toBe(MAX_SESSION_PREVIEW_LIMIT)
|
||||
|
||||
window.localStorage.setItem('hapi-session-preview-limit', '0')
|
||||
expect(getInitialSessionPreviewLimit()).toBe(MIN_SESSION_PREVIEW_LIMIT)
|
||||
|
||||
window.localStorage.setItem('hapi-session-preview-limit', '120')
|
||||
expect(getInitialSessionPreviewLimit()).toBe(MAX_SESSION_PREVIEW_LIMIT)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,117 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
export const DEFAULT_SESSION_PREVIEW_LIMIT = 8
|
||||
export const MIN_SESSION_PREVIEW_LIMIT = 1
|
||||
export const MAX_SESSION_PREVIEW_LIMIT = 99
|
||||
const SESSION_PREVIEW_LIMIT_CHANGED_EVENT = 'hapi-session-preview-limit-changed'
|
||||
|
||||
function getSessionPreviewLimitStorageKey(): string {
|
||||
return 'hapi-session-preview-limit'
|
||||
}
|
||||
|
||||
function isBrowser(): boolean {
|
||||
return typeof window !== 'undefined' && typeof document !== 'undefined'
|
||||
}
|
||||
|
||||
function safeGetItem(key: string): string | null {
|
||||
if (!isBrowser()) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return localStorage.getItem(key)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function safeSetItem(key: string, value: string): void {
|
||||
if (!isBrowser()) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
localStorage.setItem(key, value)
|
||||
} catch {
|
||||
// Ignore storage errors
|
||||
}
|
||||
}
|
||||
|
||||
function safeRemoveItem(key: string): void {
|
||||
if (!isBrowser()) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
localStorage.removeItem(key)
|
||||
} catch {
|
||||
// Ignore storage errors
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeSessionPreviewLimit(value: number): number {
|
||||
if (!Number.isInteger(value)) {
|
||||
return DEFAULT_SESSION_PREVIEW_LIMIT
|
||||
}
|
||||
return Math.min(MAX_SESSION_PREVIEW_LIMIT, Math.max(MIN_SESSION_PREVIEW_LIMIT, value))
|
||||
}
|
||||
|
||||
function parseSessionPreviewLimit(raw: string | null): number {
|
||||
if (raw === null || raw.trim() === '') {
|
||||
return DEFAULT_SESSION_PREVIEW_LIMIT
|
||||
}
|
||||
const value = Number(raw)
|
||||
return normalizeSessionPreviewLimit(value)
|
||||
}
|
||||
|
||||
export function getInitialSessionPreviewLimit(): number {
|
||||
return parseSessionPreviewLimit(safeGetItem(getSessionPreviewLimitStorageKey()))
|
||||
}
|
||||
|
||||
export function useSessionPreviewLimit(): {
|
||||
sessionPreviewLimit: number
|
||||
setSessionPreviewLimit: (limit: number) => void
|
||||
} {
|
||||
const [sessionPreviewLimit, setSessionPreviewLimitState] = useState<number>(getInitialSessionPreviewLimit)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBrowser()) {
|
||||
return
|
||||
}
|
||||
|
||||
const onStorage = (event: StorageEvent) => {
|
||||
if (event.key !== getSessionPreviewLimitStorageKey()) {
|
||||
return
|
||||
}
|
||||
setSessionPreviewLimitState(parseSessionPreviewLimit(event.newValue))
|
||||
}
|
||||
|
||||
const onLocalChange = (event: Event) => {
|
||||
const next = event instanceof CustomEvent ? event.detail : null
|
||||
if (typeof next === 'number') {
|
||||
setSessionPreviewLimitState(normalizeSessionPreviewLimit(next))
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('storage', onStorage)
|
||||
window.addEventListener(SESSION_PREVIEW_LIMIT_CHANGED_EVENT, onLocalChange)
|
||||
return () => {
|
||||
window.removeEventListener('storage', onStorage)
|
||||
window.removeEventListener(SESSION_PREVIEW_LIMIT_CHANGED_EVENT, onLocalChange)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const setSessionPreviewLimit = useCallback((limit: number) => {
|
||||
const normalized = normalizeSessionPreviewLimit(limit)
|
||||
setSessionPreviewLimitState(normalized)
|
||||
|
||||
if (normalized === DEFAULT_SESSION_PREVIEW_LIMIT) {
|
||||
safeRemoveItem(getSessionPreviewLimitStorageKey())
|
||||
} else {
|
||||
safeSetItem(getSessionPreviewLimitStorageKey(), String(normalized))
|
||||
}
|
||||
|
||||
if (isBrowser()) {
|
||||
window.dispatchEvent(new CustomEvent(SESSION_PREVIEW_LIMIT_CHANGED_EVENT, { detail: normalized }))
|
||||
}
|
||||
}, [])
|
||||
|
||||
return { sessionPreviewLimit, setSessionPreviewLimit }
|
||||
}
|
||||
Reference in New Issue
Block a user