75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { useEffect, useRef, useState } from "react"
|
||
|
||
import { API_URL } from "../../config"
|
||
import { isLiteralUnion } from "../../utils/types"
|
||
|
||
const addErrors = ["Не удалось опубликовать объявление", 'Неверный ответ от сервера', 'Неизвестная ошибка'] as const
|
||
type AddError = typeof addErrors[number]
|
||
|
||
const isAddError = (obj: unknown): obj is AddError => isLiteralUnion(obj, addErrors)
|
||
|
||
const buttonStates = ["Опубликовать", "Загрузка...", "Опубликовано", "Отменено"] as const
|
||
type ButtonState = typeof buttonStates[number] | AddError
|
||
|
||
type AddResponse = {
|
||
Answer: boolean
|
||
}
|
||
|
||
const isAddResponse = (obj: unknown): obj is AddResponse =>
|
||
typeof obj === 'object' && obj !== null && typeof Reflect.get(obj, 'Answer') === 'boolean'
|
||
|
||
|
||
const useAddAnnouncement = () => {
|
||
const [status, setStatus] = useState<ButtonState>("Опубликовать")
|
||
|
||
const timerIdRef = useRef<number>()
|
||
const abortControllerRef = useRef<AbortController>()
|
||
|
||
const doAdd = async (formData: FormData) => {
|
||
if (status === "Загрузка...") {
|
||
abortControllerRef.current?.abort()
|
||
setStatus("Отменено")
|
||
timerIdRef.current = setTimeout(() => setStatus("Опубликовать"), 3000)
|
||
return
|
||
}
|
||
|
||
setStatus("Загрузка...")
|
||
|
||
const abortController = new AbortController()
|
||
abortControllerRef.current = abortController
|
||
|
||
try {
|
||
const res = await fetch(API_URL + "/announcement", {
|
||
method: 'PUT',
|
||
body: formData,
|
||
signal: abortController.signal
|
||
})
|
||
|
||
const data: unknown = await res.json()
|
||
|
||
if (!isAddResponse(data)) throw new Error('Неверный ответ от сервера')
|
||
|
||
if (!data.Answer) {
|
||
throw new Error("Не удалось опубликовать объявление")
|
||
}
|
||
setStatus("Опубликовано")
|
||
|
||
} catch (err) {
|
||
setStatus(isAddError(err) ? err : "Неизвестная ошибка")
|
||
timerIdRef.current = setTimeout(() => setStatus("Опубликовать"), 10000)
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
const abortController = abortControllerRef.current
|
||
return () => {
|
||
clearTimeout(timerIdRef.current)
|
||
abortController?.abort()
|
||
}
|
||
})
|
||
|
||
return { doAdd, status }
|
||
}
|
||
|
||
export default useAddAnnouncement
|