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
+52
View File
@@ -0,0 +1,52 @@
import { Alert, Button, CollapseSection, FormActions, FormCard } from '@tnsu/ui-kit';
import { AppealSection } from './sections/AppealSection';
import { AuthorSection } from './sections/AuthorSection';
import { ThankYouScreen } from './ThankYouScreen';
import { TEXTS } from './texts';
import { useFeedbackForm } from './useFeedbackForm';
import styles from './FeedbackForm.module.scss';
/** Форма обращения в HR: сбор данных, валидация, экран благодарности. */
export const FeedbackForm: React.FC = () => {
const { data, errors, status, formError, set, submit, reset } = useFeedbackForm();
if (status === 'done') {
return <ThankYouScreen isAnonymous={data.isAnonymous} onNewAppeal={reset} />;
}
return (
<FormCard title={TEXTS.formTitle} subtitle={TEXTS.pageSubtitle}>
<div className={styles.notice}>
<Alert variant="warn">{TEXTS.privacyNotice}</Alert>
</div>
{formError ? (
<div className={styles.notice}>
<Alert variant="err">{formError}</Alert>
</div>
) : null}
<CollapseSection title="Кто обращается" icon="people">
<AuthorSection data={data} errors={errors} set={set} />
</CollapseSection>
<CollapseSection title="Суть обращения" icon="chat">
<AppealSection data={data} errors={errors} set={set} />
</CollapseSection>
<FormActions>
<Button variant="ghost" type="button" onClick={reset}>
{TEXTS.actions.reset}
</Button>
<Button
variant="accent"
type="button"
onClick={submit}
disabled={status === 'submitting'}
>
{TEXTS.actions.submit}
</Button>
</FormActions>
</FormCard>
);
};