Files
hr-appeals/src/features/feedback/useFeedbackForm.ts
T
gorbenko.pavel 948ef76d17
Tests / frontend-test (pull_request) Successful in 12s
правка
2026-08-24 12:10:11 +05:00

85 lines
2.8 KiB
TypeScript

import { useCallback, useState } from 'react';
import { EMPTY_FEEDBACK, type FeedbackErrors, type IFeedbackData } from './model';
import { TEXTS } from './texts';
import { validateFeedback } from './validateFeedback';
export type SubmitStatus = 'idle' | 'submitting' | 'done';
export interface IFeedbackForm {
data: IFeedbackData;
errors: FeedbackErrors;
status: SubmitStatus;
/** Общая ошибка формы (показывается над полями). */
formError: string;
set: <K extends keyof IFeedbackData>(key: K, value: IFeedbackData[K]) => void;
submit: () => void;
reset: () => void;
}
/**
* Состояние формы обращения: данные, валидация, отправка.
* Отправка идёт через nginx (/api/... -> hr-appeals-auth) — сервис сам
* меняет её на app-only токен и создаёт элемент в списке SharePoint.
*/
export function useFeedbackForm(): IFeedbackForm {
const [data, setData] = useState<IFeedbackData>(EMPTY_FEEDBACK);
const [errors, setErrors] = useState<FeedbackErrors>({});
const [formError, setFormError] = useState('');
const [status, setStatus] = useState<SubmitStatus>('idle');
const set = useCallback(
<K extends keyof IFeedbackData>(key: K, value: IFeedbackData[K]): void => {
setData((prev) => ({ ...prev, [key]: value }));
// Ошибку поля снимаем сразу при правке — иначе она висит до повторной отправки.
setErrors((prev) => {
if (!prev[key]) return prev;
const next = { ...prev };
delete next[key];
return next;
});
},
[]
);
const submit = useCallback((): void => {
const found = validateFeedback(data);
setErrors(found);
if (Object.keys(found).length > 0) {
setFormError(TEXTS.errors.hasErrors);
return;
}
setFormError('');
setStatus('submitting');
fetch('/api/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(async (response) => {
if (!response.ok) {
const body = await response.json().catch(() => null);
throw new Error(body?.error ?? `Сервер вернул ${response.status}`);
}
setStatus('done');
})
.catch((error) => {
// eslint-disable-next-line no-console
console.error('Не удалось отправить обращение:', error);
setFormError(TEXTS.errors.submitFailed);
setStatus('idle');
});
}, [data]);
const reset = useCallback((): void => {
setData(EMPTY_FEEDBACK);
setErrors({});
setFormError('');
setStatus('idle');
}, []);
return { data, errors, status, formError, set, submit, reset };
}