27 lines
1.2 KiB
TypeScript
27 lines
1.2 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { request, type Validation } from './api.ts'
|
|
|
|
/**
|
|
* Asks the server to validate value at path (a .../validate endpoint) 250 ms after it last
|
|
* changed. pending is true until the answer for the current value arrives; until then the previous result stays.
|
|
*/
|
|
export function useValidation<T extends Validation>(path: string | null, value: unknown): { result: T | null; error: string; pending: boolean } {
|
|
const key = path === null ? '' : `${path}\n${JSON.stringify(value)}`
|
|
const [answer, setAnswer] = useState<{ key: string; result: T | null; error: string } | null>(null)
|
|
|
|
useEffect(() => {
|
|
if (key === '') {
|
|
return
|
|
}
|
|
const [target, body] = [key.slice(0, key.indexOf('\n')), JSON.parse(key.slice(key.indexOf('\n') + 1))]
|
|
const timer = window.setTimeout(() => {
|
|
request<T>('POST', target, { value: body })
|
|
.then((result) => setAnswer({ key, result, error: '' }))
|
|
.catch((caught: Error) => setAnswer({ key, result: null, error: caught.message }))
|
|
}, 250)
|
|
return () => window.clearTimeout(timer)
|
|
}, [key])
|
|
|
|
return { result: answer?.result ?? null, error: answer?.error ?? '', pending: key !== '' && answer?.key !== key }
|
|
}
|