porridger/front/src/hooks/api/useAddAnnouncement.ts

75 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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