feat: форма обращения сотрудника в HR департамент

Переносит вопросы из Microsoft Forms в собственный интерфейс: компания,
анонимность, ФИО и должность, вид обращения, описание ситуации и предложение.

Поля автора скрываются при анонимном обращении, а не блокируются: требовать ФИО
у анонима — противоречие, а серое неактивное поле выглядит как ошибка формы.

Состояние целиком в useFeedbackForm, правила заполнения — в отдельной чистой
функции validateFeedback: её можно покрыть тестами без React.

Отправки пока нет — по договорённости делаем только UI, submit пишет данные в
консоль (TODO в useFeedbackForm).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 18:15:10 +05:00
parent e921062e3b
commit 010f78b138
18 changed files with 739 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
import type { ISelectOption } from '@tnsu/ui-kit';
/** Вид обращения. Union вместо строк, чтобы опечатку поймал компилятор. */
export type AppealKind = 'complaint' | 'suggestion' | 'other';
/** Данные формы обращения. Одна плоская структура — один источник истины. */
export interface IFeedbackData {
company: string;
/** true — автор не указывает себя и не получит ответ. */
isAnonymous: boolean;
fullName: string;
position: string;
wantsFeedback: boolean;
kind: AppealKind;
/** Заполняется только при kind === 'other'. */
kindOther: string;
situation: string;
suggestion: string;
}
/**
* Список компаний. ПРЕДПОЛОЖЕНИЕ: в исходной форме была видна только
* «ТОО АСТЕЛ-К»; остальные значения нужно уточнить у заказчика формы.
*/
export const COMPANY_OPTIONS: ISelectOption[] = [
{ value: 'astel-k', label: 'ТОО АСТЕЛ-К' }
];
export const KIND_OPTIONS: ISelectOption[] = [
{ value: 'complaint', label: 'Жалоба' },
{ value: 'suggestion', label: 'Предложение' },
{ value: 'other', label: 'Другое' }
];
export const EMPTY_FEEDBACK: IFeedbackData = {
company: '',
isAnonymous: false,
fullName: '',
position: '',
wantsFeedback: false,
kind: 'complaint',
kindOther: '',
situation: '',
suggestion: ''
};
/** Ключи полей, по которым показываем ошибку валидации. */
export type FeedbackErrors = Partial<Record<keyof IFeedbackData, string>>;