fix: заявки рекрутинга не давали отправить без выьбранного проекта, но пропускали пустую матрицу согласования
Tests / frontend-test (push) Successful in 1m23s
Tests / frontend-test (push) Successful in 1m23s
This commit is contained in:
@@ -196,10 +196,20 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
||||
|
||||
// При совмещении (2+ компании в «Организация») нужно явно указать, какая из них основная.
|
||||
const mainCompanyMissing = data.Companies.length >= 2 && !data.MainCompanyId;
|
||||
const isValid = data.HireCandidateName.trim().length > 0 && data.Position.trim().length > 0 && !mainCompanyMissing;
|
||||
// ProjectId обязателен (а не просто текст Project): маршрут резолвится ПО
|
||||
// ПРОЕКТУ (ByProject, см. projectId выше), и без выбранного из списка
|
||||
// варианта (id) approval-route вернёт 404 — форма должна не пускать на
|
||||
// отправку раньше, чем выяснится, что маршрут вообще некому строить (баг:
|
||||
// раньше это не проверялось, и заявка молча уходила на согласование с
|
||||
// пустой матрицей).
|
||||
const isValid =
|
||||
data.HireCandidateName.trim().length > 0 &&
|
||||
data.Position.trim().length > 0 &&
|
||||
!!data.ProjectId &&
|
||||
!mainCompanyMissing;
|
||||
const validate = (): string | undefined => {
|
||||
if (mainCompanyMissing) return 'Выбрано несколько организаций — укажите, какая из них основное место работы.';
|
||||
if (!isValid) return 'Заполните обязательные поля: Ф.И.О. кандидата, Должность.';
|
||||
if (!isValid) return 'Заполните обязательные поля: Ф.И.О. кандидата, Должность, Проект (выберите вариант из списка).';
|
||||
if (requestTypeIdState.error) return `Не удалось определить тип заявки: ${requestTypeIdState.error}`;
|
||||
if (!requestTypeId) return 'Тип заявки ещё определяется — подождите немного и повторите.';
|
||||
return undefined;
|
||||
@@ -296,6 +306,20 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
||||
const validateSubmit = (): string | undefined => {
|
||||
const formError = validate();
|
||||
if (formError) return formError;
|
||||
if (matrix.error) {
|
||||
return `Не удалось определить маршрут согласования: ${matrix.error}. Попробуйте ещё раз или обратитесь к администратору.`;
|
||||
}
|
||||
if (matrix.loading) {
|
||||
return 'Маршрут согласования ещё формируется — подождите немного и повторите.';
|
||||
}
|
||||
// Матрица пуста (не только «есть шаг без человека») — раньше это молча
|
||||
// пропускалось (findUnassignedStep на пустом массиве ошибки не даёт), и
|
||||
// заявка уходила на согласование без единого согласующего. У фазы
|
||||
// исполнения (executors) пустой список — нормальное состояние (не у
|
||||
// всех маршрутов есть шаги исполнения), там эта проверка не нужна.
|
||||
if (matrix.rows.length === 0) {
|
||||
return 'Маршрут согласования не найден для выбранного проекта — обратитесь к администратору.';
|
||||
}
|
||||
const unassignedApproverError = unassignedStepMessage(
|
||||
matrix.rows,
|
||||
(r) => `Шаг ${r.order} маршрута согласования («${r.position || 'без должности'}») без назначенного человека — выберите согласующего или удалите шаг.`
|
||||
|
||||
@@ -49,7 +49,7 @@ export const ApplicationSection: React.FC<ISectionProps> = ({ data, set, context
|
||||
shares={data.CompanyShares}
|
||||
onSharesChange={(v) => set('CompanyShares', v)}
|
||||
/>
|
||||
<FormField label="1.2 Проект" htmlFor="Project" full>
|
||||
<FormField label="1.2 Проект" htmlFor="Project" required full>
|
||||
<ProjectPicker
|
||||
context={context}
|
||||
id="Project"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import { CollapseSection, FormField, TextInput } from '../../../shared/ui';
|
||||
import { PositionPicker } from '../../../shared/dictionary';
|
||||
import { ISectionProps } from '../model';
|
||||
|
||||
export const CandidateSection: React.FC<ISectionProps> = ({ data, set }) => (
|
||||
export const CandidateSection: React.FC<ISectionProps> = ({ data, set, context }) => (
|
||||
<CollapseSection title="2. Кандидат" icon="people">
|
||||
<FormField label="2.1 Ф.И.О. кандидата" htmlFor="HireCandidateName" required full>
|
||||
<TextInput id="HireCandidateName" value={data.HireCandidateName} onChange={(v) => set('HireCandidateName', v)} />
|
||||
@@ -11,7 +12,13 @@ export const CandidateSection: React.FC<ISectionProps> = ({ data, set }) => (
|
||||
<TextInput id="HireHireDate" type="date" value={data.HireHireDate} onChange={(v) => set('HireHireDate', v)} />
|
||||
</FormField>
|
||||
<FormField label="2.3 Должность" htmlFor="Position" required>
|
||||
<TextInput id="Position" value={data.Position} onChange={(v) => set('Position', v)} />
|
||||
<PositionPicker
|
||||
context={context}
|
||||
id="Position"
|
||||
value={data.Position}
|
||||
onChange={(v) => set('Position', v)}
|
||||
placeholder="Начните вводить название должности…"
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="2.4 Вид работ" htmlFor="WorkKind">
|
||||
<TextInput id="WorkKind" value={data.WorkKind} onChange={(v) => set('WorkKind', v)} />
|
||||
|
||||
Reference in New Issue
Block a user