feat: испытательный срок в подборе, дата приёма по приезду, HR-формы для тестировщиков
Tests / frontend-test (push) Successful in 1m19s

This commit is contained in:
Тимур Городецкий
2026-09-24 16:10:54 +05:00
parent b7bd8537a4
commit 17e7c634d5
18 changed files with 303 additions and 84 deletions
@@ -62,6 +62,13 @@ export interface IFormData {
BusinessTripsDetails: string;
BusinessTripsDetailsOther: string;
// Условия работы
/**
* Префикс Selection — обход коллизии internalName: в «Заявке на прием» уже
* есть колонка ProbationPeriod, а одинаковые имена в разных списках сайта
* ломают тип/title колонки (см. историю с WorkSchedule).
*/
SelectionProbationPeriod: string;
SelectionProbationPeriodOther: string;
RateProbation: string;
RateAfterProbation: string;
PieceworkPay: boolean;
@@ -122,6 +129,8 @@ export const EMPTY_DATA: IFormData = {
BusinessTrips: false,
BusinessTripsDetails: '',
BusinessTripsDetailsOther: '',
SelectionProbationPeriod: '',
SelectionProbationPeriodOther: '',
RateProbation: '',
RateAfterProbation: '',
PieceworkPay: false,
@@ -245,6 +254,18 @@ export const WORK_EXPERIENCE_OPTIONS: ISelectOption[] = [
{ value: 'От 5 лет и выше', label: 'От 5 лет и выше' }
];
/**
* Варианты «Испытательный срок» — совпадают с choices колонки
* SelectionProbationPeriod и с тем же полем в «Заявке на прием».
*/
export const PROBATION_PERIOD_OPTIONS: ISelectOption[] = [
{ value: '1 месяц', label: '1 месяц' },
{ value: '2 месяца', label: '2 месяца' },
{ value: '3 месяца', label: '3 месяца' },
{ value: '6 месяцев', label: '6 месяцев' },
{ value: OTHER_VALUE, label: OTHER_VALUE }
];
/** Варианты «Режим работы» — совпадают с choices колонки WorkSchedule. */
export const WORK_SCHEDULE_OPTIONS: ISelectOption[] = [
{ value: '5/2', label: '5/2' },
@@ -35,6 +35,8 @@
{ "internalName": "BusinessTripsDetails", "title": "Командировки — продолжительность / частота", "type": "Choice", "choices": ["Редко (1–2 раза в год)", "Ежеквартально", "Ежемесячно", "Еженедельно", "Постоянные разъезды", "Вахтовый метод", "Другое"] },
{ "internalName": "BusinessTripsDetailsOther", "title": "Командировки — частота (другое)", "type": "Text" },
{ "internalName": "SelectionProbationPeriod", "title": "Испытательный срок", "type": "Choice", "choices": ["1 месяц", "2 месяца", "3 месяца", "6 месяцев", "Другое"] },
{ "internalName": "SelectionProbationPeriodOther", "title": "Испытательный срок (другое)", "type": "Text" },
{ "internalName": "RateProbation", "title": "Ставка на ИС", "type": "Number", "decimals": 2 },
{ "internalName": "RateAfterProbation", "title": "Ставка после ИС", "type": "Number", "decimals": 2 },
{ "internalName": "Awards", "title": "Премии", "type": "Note" },
@@ -14,6 +14,7 @@ import {
ISectionProps,
PERSON_PLACEHOLDER,
OTHER_VALUE,
PROBATION_PERIOD_OPTIONS,
WORK_SCHEDULE_OPTIONS,
WORK_HOURS_OPTIONS,
WORKPLACE_PROVISION_OPTIONS,
@@ -25,28 +26,49 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
context,
}) => (
<CollapseSection title="5. Условия работы" icon="chart">
<FormField label="5.1 Ставка на ИС" htmlFor="RateProbation" required>
<FormField label="5.1 Испытательный срок" htmlFor="SelectionProbationPeriod" required>
<Select
id="SelectionProbationPeriod"
value={data.SelectionProbationPeriod}
onChange={(v) => {
set("SelectionProbationPeriod", v);
if (v !== OTHER_VALUE) set("SelectionProbationPeriodOther", "");
}}
options={PROBATION_PERIOD_OPTIONS}
placeholder="— выберите —"
/>
</FormField>
{data.SelectionProbationPeriod === OTHER_VALUE && (
<FormField label="Испытательный срок (другое)" htmlFor="SelectionProbationPeriodOther">
<TextInput
id="SelectionProbationPeriodOther"
value={data.SelectionProbationPeriodOther}
onChange={(v) => set("SelectionProbationPeriodOther", v)}
/>
</FormField>
)}
<FormField label="5.2 Ставка на ИС" htmlFor="RateProbation" required>
<MoneyInput
id="RateProbation"
value={data.RateProbation}
onChange={(v) => set("RateProbation", v)}
/>
</FormField>
<FormField label="5.2 Ставка после ИС" htmlFor="RateAfterProbation" required>
<FormField label="5.3 Ставка после ИС" htmlFor="RateAfterProbation" required>
<MoneyInput
id="RateAfterProbation"
value={data.RateAfterProbation}
onChange={(v) => set("RateAfterProbation", v)}
/>
</FormField>
<FormField label="5.3 Сдельная оплата труда">
<FormField label="5.4 Сдельная оплата труда">
<Toggle
checked={data.PieceworkPay}
onChange={(v) => set("PieceworkPay", v)}
onLabel="Да"
/>
</FormField>
<FormField label="5.4 График работы" htmlFor="WorkSchedule" required>
<FormField label="5.5 График работы" htmlFor="WorkSchedule" required>
<Select
id="WorkSchedule"
value={data.WorkSchedule}
@@ -67,7 +89,7 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
/>
</FormField>
)}
<FormField label="5.5 Время работы" htmlFor="WorkHours" required>
<FormField label="5.6 Время работы" htmlFor="WorkHours" required>
<Select
id="WorkHours"
value={data.WorkHours}
@@ -88,14 +110,14 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
/>
</FormField>
)}
<FormField label="5.6 Материальная ответственность (строительные площадки, склады)">
<FormField label="5.7 Материальная ответственность (строительные площадки, склады)">
<Toggle
checked={data.MaterialResponsibility}
onChange={(v) => set("MaterialResponsibility", v)}
onLabel="Да"
/>
</FormField>
<FormField label="5.7 Обеспечение рабочего места" required full>
<FormField label="5.8 Обеспечение рабочего места" required full>
<MultiChoiceField
value={data.WorkplaceProvision}
onChange={(v) => set("WorkplaceProvision", v)}
@@ -104,14 +126,14 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
placeholder="Выберите категорию"
/>
</FormField>
<FormField label="5.8 Охватывается реферальной программой">
<FormField label="5.9 Охватывается реферальной программой">
<Toggle
checked={data.ReferralProgram}
onChange={(v) => set("ReferralProgram", v)}
onLabel="Да"
/>
</FormField>
<FormField label="5.9 Предполагаемый наставник">
<FormField label="5.10 Предполагаемый наставник">
<PeopleField
context={context}
value={data.ProposedMentor}
@@ -119,7 +141,7 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
placeholder={PERSON_PLACEHOLDER}
/>
</FormField>
<FormField label="5.10 Непосредственный руководитель" required>
<FormField label="5.11 Непосредственный руководитель" required>
<PeopleField
context={context}
value={data.DirectManager}
@@ -127,7 +149,7 @@ export const ConditionsSection: React.FC<ISectionProps> = ({
placeholder={PERSON_PLACEHOLDER}
/>
</FormField>
<FormField label="5.11 Кто принимает решение о приеме (собеседования)" required full>
<FormField label="5.12 Кто принимает решение о приеме (собеседования)" required full>
<PeopleFieldMulti
context={context}
value={data.HiringDecisionMaker}
@@ -9,8 +9,9 @@ import { IFormData } from './model';
* ReferralProgram) и условные «другое»-подполя в проверку не входят — у
* булевых нет пустого состояния, а «другое» раскрывается только при выборе
* соответствующего варианта в уже обязательном родительском поле.
* 5.9 «Предполагаемый наставник» (ProposedMentor) сделан необязательным
* 5.10 «Предполагаемый наставник» (ProposedMentor) сделан необязательным
* по просьбе Тимура (2026-09-24) — не всегда есть кого назначить заранее.
* 5.1 «Испытательный срок» добавлен 2026-09-24 — нумерация раздела 5 сдвинута на 1.
*/
const REQUIRED_FIELDS: ReadonlyArray<{ label: string; ok: (d: IFormData) => boolean }> = [
{ label: '1.3 дата подачи заявки', ok: (d) => !!d.SubmitDate },
@@ -25,13 +26,14 @@ const REQUIRED_FIELDS: ReadonlyArray<{ label: string; ok: (d: IFormData) => bool
{ label: '3.5 личностные характеристики', ok: (d) => !!d.PersonalTraits.trim() },
{ label: '3.6 образование', ok: (d) => !!d.Education },
{ label: '3.7 опыт работы', ok: (d) => !!d.WorkExperience },
{ label: '5.1 ставка на ИС', ok: (d) => !!d.RateProbation.trim() },
{ label: '5.2 ставка после ИС', ok: (d) => !!d.RateAfterProbation.trim() },
{ label: '5.4 график работы', ok: (d) => !!d.WorkSchedule },
{ label: '5.5 время работы', ok: (d) => !!d.WorkHours },
{ label: '5.7 обеспечение рабочего места', ok: (d) => d.WorkplaceProvision.length > 0 },
{ label: '5.10 непосредственный руководитель', ok: (d) => !!d.DirectManager },
{ label: '5.11 кто принимает решение о приёме', ok: (d) => d.HiringDecisionMaker.length > 0 }
{ label: '5.1 испытательный срок', ok: (d) => !!d.SelectionProbationPeriod },
{ label: '5.2 ставка на ИС', ok: (d) => !!d.RateProbation.trim() },
{ label: '5.3 ставка после ИС', ok: (d) => !!d.RateAfterProbation.trim() },
{ label: '5.5 график работы', ok: (d) => !!d.WorkSchedule },
{ label: '5.6 время работы', ok: (d) => !!d.WorkHours },
{ label: '5.8 обеспечение рабочего места', ok: (d) => d.WorkplaceProvision.length > 0 },
{ label: '5.11 непосредственный руководитель', ok: (d) => !!d.DirectManager },
{ label: '5.12 кто принимает решение о приёме', ok: (d) => d.HiringDecisionMaker.length > 0 }
];
/** Подписи незаполненных обязательных-для-отправки полей (пусто — всё заполнено). */