85 lines
2.8 KiB
TypeScript
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 };
|
|
}
|