diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx b/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx index 38757a4..5aed7dc 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx +++ b/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx @@ -108,9 +108,9 @@ const RecruitingSelectionForm: React.FC = ({ requestType, con (login) => approval.getJobTitle(login) ); - const isValid = !!(data.Responsible && data.DepartmentName.trim() && data.Position.trim()); + const isValid = !!(data.Responsible && data.DepartmentName.trim() && data.Position.trim() && data.Residence); const validate = (): string | undefined => { - if (!isValid) return 'Заполните обязательные поля: ответственный за подачу, название отдела, должность.'; + if (!isValid) return 'Заполните обязательные поля: ответственный за подачу, название отдела, должность, проживание.'; if (requestTypeIdState.error) return `Не удалось определить тип заявки: ${requestTypeIdState.error}`; if (!requestTypeId) return 'Тип заявки ещё определяется — подождите немного и повторите.'; return undefined; diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/load.ts b/src/webparts/requestPortal/forms/RecruitingSelection/load.ts index 7769da4..b3879b2 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/load.ts +++ b/src/webparts/requestPortal/forms/RecruitingSelection/load.ts @@ -1,11 +1,28 @@ import { getSP } from '../../shared/pnp/pnpjs'; +import { ICompany } from '../../shared/dictionary'; import { dataListTitle } from '../../shared/listTitles'; -import { FORM_ID, IFormData, EMPTY_DATA } from './model'; +import { FORM_ID, IFormData, EMPTY_DATA, ILanguageLevel } from './model'; + +/** Безопасный разбор JSON-массива из Note-колонки (пустой при ошибке/пустом). */ +function parseJsonArray(raw: unknown): T[] { + if (typeof raw !== 'string' || raw.trim() === '') return []; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? (parsed as T[]) : []; + } catch { + return []; + } +} // Категории полей — определяют, как читать значение из элемента списка. const PERSON_FIELDS: (keyof IFormData)[] = ['Responsible', 'ProposedMentor', 'DirectManager']; const MULTI_PERSON_FIELDS: (keyof IFormData)[] = ['HiringDecisionMaker']; -const BOOL_FIELDS: (keyof IFormData)[] = ['IsRegistered', 'IsApproved', 'CompletionMark', 'MaterialResponsibility']; +const BOOL_FIELDS: (keyof IFormData)[] = [ + 'MaterialResponsibility', + 'PieceworkPay', + 'ReferralProgram', + 'BusinessTrips' +]; const DATE_FIELDS: (keyof IFormData)[] = ['SubmitDate', 'ClosingDeadline']; type PersonValue = { EMail?: string } | undefined; @@ -23,21 +40,39 @@ export async function loadSelectionRequest(itemId: number): Promise PERSON_FIELDS.indexOf(k) !== -1 || MULTI_PERSON_FIELDS.indexOf(k) !== -1; - // Скалярные поля — по имени; поля-люди — вложенный EMail (+ expand). - const scalarSelects = keys.filter((k) => !isPerson(k)); + // Скалярные поля — по имени; поля-люди — вложенный EMail (+ expand); + // Companies/Languages/Programs хранятся в Note-колонках *Json (не одноимёнными колонками). + const jsonKeys: (keyof IFormData)[] = ['Companies', 'Languages', 'Programs', 'WorkplaceProvision']; + const scalarSelects = keys.filter((k) => !isPerson(k) && jsonKeys.indexOf(k) === -1); const personSelects = [...PERSON_FIELDS, ...MULTI_PERSON_FIELDS].map((k) => `${k}/EMail`); const expands = [...PERSON_FIELDS, ...MULTI_PERSON_FIELDS]; const item = (await getSP() .web.lists.getByTitle(dataListTitle(FORM_ID)) .items.getById(itemId) - .select(...scalarSelects, 'RequestStatus', 'RequestUniqueCode', ...personSelects) + .select( + ...scalarSelects, + 'CompaniesJson', + 'LanguagesJson', + 'ProgramsJson', + 'WorkplaceProvisionJson', + 'RequestStatus', + 'RequestUniqueCode', + ...personSelects + ) .expand(...expands)()) as Record; const data: IFormData = { ...EMPTY_DATA }; const writable = data as unknown as Record; + writable.Companies = parseJsonArray(item.CompaniesJson); + writable.Languages = parseJsonArray(item.LanguagesJson); + writable.Programs = parseJsonArray(item.ProgramsJson); + writable.WorkplaceProvision = parseJsonArray(item.WorkplaceProvisionJson); keys.forEach((key) => { + if (jsonKeys.indexOf(key) !== -1) { + return; // уже разобрали из *Json + } if (PERSON_FIELDS.indexOf(key) !== -1) { writable[key] = (item[key] as PersonValue)?.EMail || ''; } else if (MULTI_PERSON_FIELDS.indexOf(key) !== -1) { diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/model.ts b/src/webparts/requestPortal/forms/RecruitingSelection/model.ts index 35a1b92..146a94b 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/model.ts +++ b/src/webparts/requestPortal/forms/RecruitingSelection/model.ts @@ -1,5 +1,6 @@ import { WebPartContext } from '@microsoft/sp-webpart-base'; import { ISelectOption } from '../../shared/ui'; +import { ICompany } from '../../shared/dictionary'; import { RequestTypeId } from '../../models/types'; /** @@ -18,47 +19,47 @@ export interface IFormData { SubmitDate: string; ClosingDeadline: string; OpenReason: string; - IsRegistered: boolean; - IsApproved: boolean; - CompletionMark: boolean; + OpenReasonDetails: string; + Companies: ICompany[]; + ObjectProject: string; + ObjectProjectId: string; + ObjectProjectCode: string; // Отдел DepartmentName: string; - DepartmentHeadcount: string; - DepartmentGoals: string; - RelatedDepartments: string; + OpenVacanciesCount: string; // Вакансия Position: string; - ClassifierCode: string; EmploymentType: string; - MainFunction: string; - AdditionalFunction: string; + JobFunction: string; Competencies: string; PersonalTraits: string; Education: string; WorkExperience: string; - AdditionalEducation: string; - EvaluationCriteria: string; - PcSkills: string; - ForeignLanguages: string; + Programs: string[]; + Languages: ILanguageLevel[]; Residence: string; + ResidenceOther: string; DrivingLicense: string; - // Здоровье / командировки - HealthRestrictions: string; - BusinessTrips: string; + // Командировки + BusinessTrips: boolean; + BusinessTripsDetails: string; + BusinessTripsDetailsOther: string; // Условия работы RateProbation: string; RateAfterProbation: string; Awards: string; Bonuses: string; CompensationPackage: string; + PieceworkPay: boolean; WorkSchedule: string; - Location: string; + WorkScheduleOther: string; + WorkHours: string; + WorkHoursOther: string; MaterialResponsibility: boolean; - WorkplaceProvision: string; + WorkplaceProvision: string[]; ProposedMentor: string; DirectManager: string; - DevelopmentPrograms: string; - DesiredTraining: string; + ReferralProgram: boolean; HiringDecisionMaker: string[]; } @@ -77,43 +78,43 @@ export const EMPTY_DATA: IFormData = { SubmitDate: '', ClosingDeadline: '', OpenReason: '', - IsRegistered: false, - IsApproved: false, - CompletionMark: false, + OpenReasonDetails: '', + Companies: [], + ObjectProject: '', + ObjectProjectId: '', + ObjectProjectCode: '', DepartmentName: '', - DepartmentHeadcount: '', - DepartmentGoals: '', - RelatedDepartments: '', + OpenVacanciesCount: '', Position: '', - ClassifierCode: '', EmploymentType: '', - MainFunction: '', - AdditionalFunction: '', + JobFunction: '', Competencies: '', PersonalTraits: '', Education: '', WorkExperience: '', - AdditionalEducation: '', - EvaluationCriteria: '', - PcSkills: '', - ForeignLanguages: '', + Programs: [], + Languages: [], Residence: '', + ResidenceOther: '', DrivingLicense: '', - HealthRestrictions: '', - BusinessTrips: '', + BusinessTrips: false, + BusinessTripsDetails: '', + BusinessTripsDetailsOther: '', RateProbation: '', RateAfterProbation: '', Awards: '', Bonuses: '', CompensationPackage: '', + PieceworkPay: false, WorkSchedule: '', - Location: '', + WorkScheduleOther: '', + WorkHours: '', + WorkHoursOther: '', MaterialResponsibility: false, - WorkplaceProvision: '', + WorkplaceProvision: [], ProposedMentor: '', DirectManager: '', - DevelopmentPrograms: '', - DesiredTraining: '', + ReferralProgram: false, HiringDecisionMaker: [] }; @@ -123,5 +124,127 @@ export const EMPLOYMENT_TYPE_OPTIONS: ISelectOption[] = [ { value: 'Временная', label: 'Временная' } ]; +/** Значение-триггер «Другое»: при нём показываем поле ручного ввода. */ +export const OTHER_VALUE = 'Другое'; + +/** Причины открытия вакансии, требующие ФИО сотрудника (для условного поля). */ +export const OPEN_REASON_REPLACE = 'Замена уволенного сотрудника'; +export const OPEN_REASON_TRANSFER = 'Перевод сотрудника'; +export const OPEN_REASON_NEW = 'Новая штатная единица'; + +/** Варианты «Причина открытия вакансии» — совпадают с choices колонки OpenReason. */ +export const OPEN_REASON_OPTIONS: ISelectOption[] = [ + { value: OPEN_REASON_REPLACE, label: OPEN_REASON_REPLACE }, + { value: OPEN_REASON_TRANSFER, label: OPEN_REASON_TRANSFER }, + { value: OPEN_REASON_NEW, label: OPEN_REASON_NEW }, + { value: OTHER_VALUE, label: OTHER_VALUE } +]; + +/** Варианты «Проживание» — совпадают с choices колонки Residence. */ +export const RESIDENCE_OPTIONS: ISelectOption[] = [ + { value: 'Общежитие компании', label: 'Общежитие компании' }, + { value: 'За счёт компании', label: 'За счёт компании' }, + { value: 'За счёт кандидата', label: 'За счёт кандидата' }, + { value: OTHER_VALUE, label: OTHER_VALUE } +]; + +/** Владение одним языком: язык + требуемый уровень. Хранится JSON-массивом. */ +export interface ILanguageLevel { + language: string; + level: string; +} + +/** Иностранные языки, актуальные для Казахстана (фикс. набор строк таблицы). */ +export const LANGUAGES: string[] = ['Казахский', 'Русский', 'Английский', 'Китайский', 'Турецкий']; + +/** Шкала уровней владения языком. */ +export const LANGUAGE_LEVEL_OPTIONS: ISelectOption[] = [ + { value: 'Начинающий', label: 'Начинающий' }, + { value: 'Базовый', label: 'Базовый' }, + { value: 'Средний', label: 'Средний' }, + { value: 'Продвинутый', label: 'Продвинутый' }, + { value: 'Свободный', label: 'Свободный' } +]; + +/** + * Программы (ПО) — ВРЕМЕННЫЙ список, пока нет справочника в API. Используется в + * мультивыборе «Необходимые знания в программах». Меняется здесь одним местом. + */ +export const SOFTWARE_OPTIONS: ISelectOption[] = [ + { value: '1С:Предприятие', label: '1С:Предприятие' }, + { value: 'MS Word', label: 'MS Word' }, + { value: 'MS Excel', label: 'MS Excel' }, + { value: 'MS PowerPoint', label: 'MS PowerPoint' }, + { value: 'MS Outlook', label: 'MS Outlook' }, + { value: 'MS Project', label: 'MS Project' }, + { value: 'AutoCAD', label: 'AutoCAD' }, + { value: 'Revit', label: 'Revit' }, + { value: 'ArchiCAD', label: 'ArchiCAD' }, + { value: 'Компас-3D', label: 'Компас-3D' }, + { value: 'Primavera', label: 'Primavera' }, + { value: 'SAP', label: 'SAP' }, + { value: 'Adobe Photoshop', label: 'Adobe Photoshop' } +]; + +/** Категории «Обеспечение рабочего места» (+ «Другое» через allowOther). */ +export const WORKPLACE_PROVISION_OPTIONS: ISelectOption[] = [ + { value: 'Оргтехника', label: 'Оргтехника' }, + { value: 'СИЗ', label: 'СИЗ' }, + { value: 'Программное обеспечение', label: 'Программное обеспечение' } +]; + +/** Варианты «Командировки — продолжительность/частота» — совпадают с choices BusinessTripsDetails. */ +export const BUSINESS_TRIP_OPTIONS: ISelectOption[] = [ + { value: 'Редко (1–2 раза в год)', label: 'Редко (1–2 раза в год)' }, + { value: 'Ежеквартально', label: 'Ежеквартально' }, + { value: 'Ежемесячно', label: 'Ежемесячно' }, + { value: 'Еженедельно', label: 'Еженедельно' }, + { value: 'Постоянные разъезды', label: 'Постоянные разъезды' }, + { value: 'Вахтовый метод', label: 'Вахтовый метод' }, + { value: OTHER_VALUE, label: OTHER_VALUE } +]; + +/** Варианты «Образование» (РК) — совпадают с choices колонки Education. */ +export const EDUCATION_OPTIONS: ISelectOption[] = [ + { value: 'Среднее', label: 'Среднее' }, + { value: 'Техническое и профессиональное (ТиПО)', label: 'Техническое и профессиональное (ТиПО)' }, + { value: 'Незаконченное высшее', label: 'Незаконченное высшее' }, + { value: 'Высшее — бакалавриат', label: 'Высшее — бакалавриат' }, + { value: 'Высшее — магистратура', label: 'Высшее — магистратура' }, + { value: 'Послевузовское (докторантура / PhD)', label: 'Послевузовское (докторантура / PhD)' } +]; + +/** Варианты «Опыт работы» — совпадают с choices колонки WorkExperience. */ +export const WORK_EXPERIENCE_OPTIONS: ISelectOption[] = [ + { value: 'Без опыта', label: 'Без опыта' }, + { value: 'До 3 лет', label: 'До 3 лет' }, + { value: 'От 3 до 5 лет', label: 'От 3 до 5 лет' }, + { value: 'От 5 лет и выше', label: 'От 5 лет и выше' } +]; + +/** Варианты «Режим работы» — совпадают с choices колонки WorkSchedule. */ +export const WORK_SCHEDULE_OPTIONS: ISelectOption[] = [ + { value: '5/2', label: '5/2' }, + { value: 'Вахтовый 30/30', label: 'Вахтовый 30/30' }, + { value: '20/10', label: '20/10' }, + { value: '30/15', label: '30/15' }, + { value: '22/8', label: '22/8' }, + { value: '15/15', label: '15/15' }, + { value: '6/1', label: '6/1' }, + { value: '1/2', label: '1/2' }, + { value: '2/2', label: '2/2' }, + { value: OTHER_VALUE, label: OTHER_VALUE } +]; + +/** Варианты «Время работы» — совпадают с choices колонки WorkHours. */ +export const WORK_HOURS_OPTIONS: ISelectOption[] = [ + { value: '8-5', label: '8-5' }, + { value: '9-6', label: '9-6' }, + { value: '7-7', label: '7-7' }, + { value: '8-8', label: '8-8' }, + { value: '9-9', label: '9-9' }, + { value: OTHER_VALUE, label: OTHER_VALUE } +]; + /** Плейсхолдер для полей-людей. */ export const PERSON_PLACEHOLDER = 'Начните вводить имя сотрудника…'; diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/provisioning.json b/src/webparts/requestPortal/forms/RecruitingSelection/provisioning.json index 30af6ea..d8dd602 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/provisioning.json +++ b/src/webparts/requestPortal/forms/RecruitingSelection/provisioning.json @@ -5,49 +5,49 @@ { "internalName": "RequestStatus", "title": "Статус", "type": "Choice", "choices": ["Черновик", "На согласовании", "Согласовано", "Отклонено", "Возвращена на доработку", "Выполнение", "Закрыта"] }, { "internalName": "Responsible", "title": "Ответственный за подачу заявки", "type": "User", "userSelectionMode": "PeopleOnly", "required": true }, { "internalName": "SubmitDate", "title": "Дата подачи заявки", "type": "DateTime", "dateOnly": true }, - { "internalName": "IsRegistered", "title": "Зарегистрирована", "type": "Boolean" }, - { "internalName": "IsApproved", "title": "Одобрена", "type": "Boolean" }, - { "internalName": "OpenReason", "title": "Причина открытия вакансии", "type": "Note" }, + { "internalName": "OpenReason", "title": "Причина открытия вакансии", "type": "Choice", "choices": ["Замена уволенного сотрудника", "Перевод сотрудника", "Новая штатная единица", "Другое"] }, + { "internalName": "OpenReasonDetails", "title": "Причина открытия — ФИО / уточнение", "type": "Text" }, + { "internalName": "CompaniesJson", "title": "Компании (JSON)", "type": "Note" }, + { "internalName": "ObjectProject", "title": "Объект/Проект", "type": "Text" }, + { "internalName": "ObjectProjectId", "title": "Объект/Проект — Id", "type": "Text" }, + { "internalName": "ObjectProjectCode", "title": "Объект/Проект — код", "type": "Text" }, { "internalName": "ClosingDeadline", "title": "Крайний срок закрытия", "type": "DateTime", "dateOnly": true }, - { "internalName": "CompletionMark", "title": "Отметка о выполнении", "type": "Boolean" }, { "internalName": "DepartmentName", "title": "Название отдела/департамента", "type": "Text", "required": true }, - { "internalName": "DepartmentHeadcount", "title": "Количество сотрудников в отделе", "type": "Number" }, - { "internalName": "DepartmentGoals", "title": "Цели, стоящие перед отделом", "type": "Note" }, - { "internalName": "RelatedDepartments", "title": "Смежные отделы по бизнес-процессам", "type": "Note" }, + { "internalName": "OpenVacanciesCount", "title": "Количество открытых вакансий", "type": "Number" }, { "internalName": "Position", "title": "Должность", "type": "Text", "required": true }, - { "internalName": "ClassifierCode", "title": "Код по классификатору", "type": "Text" }, { "internalName": "EmploymentType", "title": "Характер занятости", "type": "Choice", "choices": ["Постоянная", "Временная"] }, - { "internalName": "MainFunction", "title": "Основной функционал", "type": "Note" }, - { "internalName": "AdditionalFunction", "title": "Дополнительный функционал", "type": "Note" }, + { "internalName": "JobFunction", "title": "Функционал", "type": "Note" }, { "internalName": "Competencies", "title": "Компетенции", "type": "Note" }, { "internalName": "PersonalTraits", "title": "Личностные характеристики", "type": "Note" }, - { "internalName": "Education", "title": "Образование", "type": "Text" }, - { "internalName": "WorkExperience", "title": "Опыт работы", "type": "Note" }, - { "internalName": "AdditionalEducation", "title": "Дополнительное образование", "type": "Note" }, - { "internalName": "EvaluationCriteria", "title": "Критерии оценки работы", "type": "Note" }, - { "internalName": "PcSkills", "title": "Уровень владения ПК и программами", "type": "Note" }, - { "internalName": "ForeignLanguages", "title": "Иностранные языки (уровень владения)", "type": "Note" }, - { "internalName": "Residence", "title": "Проживание", "type": "Text" }, + { "internalName": "Education", "title": "Образование", "type": "Choice", "choices": ["Среднее", "Техническое и профессиональное (ТиПО)", "Незаконченное высшее", "Высшее — бакалавриат", "Высшее — магистратура", "Послевузовское (докторантура / PhD)"] }, + { "internalName": "WorkExperience", "title": "Опыт работы", "type": "Choice", "choices": ["Без опыта", "До 3 лет", "От 3 до 5 лет", "От 5 лет и выше"] }, + { "internalName": "ProgramsJson", "title": "Необходимые знания в программах (JSON)", "type": "Note" }, + { "internalName": "LanguagesJson", "title": "Иностранные языки (JSON)", "type": "Note" }, + { "internalName": "Residence", "title": "Проживание", "type": "Choice", "required": true, "choices": ["Общежитие компании", "За счёт компании", "За счёт кандидата", "Другое"] }, + { "internalName": "ResidenceOther", "title": "Проживание (другое)", "type": "Text" }, { "internalName": "DrivingLicense", "title": "Водительские права, стаж вождения", "type": "Text" }, - { "internalName": "HealthRestrictions", "title": "Приемлемые противопоказания (здоровье)", "type": "Note" }, - { "internalName": "BusinessTrips", "title": "Командировки (есть/нет и продолжительность)", "type": "Note" }, + { "internalName": "BusinessTrips", "title": "Командировки", "type": "Boolean" }, + { "internalName": "BusinessTripsDetails", "title": "Командировки — продолжительность / частота", "type": "Choice", "choices": ["Редко (1–2 раза в год)", "Ежеквартально", "Ежемесячно", "Еженедельно", "Постоянные разъезды", "Вахтовый метод", "Другое"] }, + { "internalName": "BusinessTripsDetailsOther", "title": "Командировки — частота (другое)", "type": "Text" }, { "internalName": "RateProbation", "title": "Ставка на ИС", "type": "Number", "decimals": 2 }, { "internalName": "RateAfterProbation", "title": "Ставка после ИС", "type": "Number", "decimals": 2 }, { "internalName": "Awards", "title": "Премии", "type": "Note" }, { "internalName": "Bonuses", "title": "Бонусы", "type": "Note" }, { "internalName": "CompensationPackage", "title": "Компенсационный пакет", "type": "Note" }, - { "internalName": "WorkSchedule", "title": "Режим работы", "type": "Text" }, - { "internalName": "Location", "title": "Локация", "type": "Text" }, + { "internalName": "PieceworkPay", "title": "Сдельная оплата труда", "type": "Boolean" }, + { "internalName": "WorkSchedule", "title": "Режим работы", "type": "Choice", "choices": ["5/2", "Вахтовый 30/30", "20/10", "30/15", "22/8", "15/15", "6/1", "1/2", "2/2", "Другое"] }, + { "internalName": "WorkScheduleOther", "title": "Режим работы (другое)", "type": "Text" }, + { "internalName": "WorkHours", "title": "Время работы", "type": "Choice", "choices": ["8-5", "9-6", "7-7", "8-8", "9-9", "Другое"] }, + { "internalName": "WorkHoursOther", "title": "Время работы (другое)", "type": "Text" }, { "internalName": "MaterialResponsibility", "title": "Материальная ответственность", "type": "Boolean" }, - { "internalName": "WorkplaceProvision", "title": "Обеспечение рабочего места", "type": "Note" }, + { "internalName": "WorkplaceProvisionJson", "title": "Обеспечение рабочего места (JSON)", "type": "Note" }, { "internalName": "ProposedMentor", "title": "Предполагаемый наставник", "type": "User", "userSelectionMode": "PeopleOnly" }, { "internalName": "DirectManager", "title": "Непосредственный руководитель", "type": "User", "userSelectionMode": "PeopleOnly" }, - { "internalName": "DevelopmentPrograms", "title": "Программы развития и обучения, периодичность", "type": "Note" }, - { "internalName": "DesiredTraining", "title": "Желаемое доп. обучение при выходе на работу", "type": "Note" }, + { "internalName": "ReferralProgram", "title": "Реферальная программа", "type": "Boolean" }, { "internalName": "HiringDecisionMaker", "title": "Кто принимает решение о приеме (собеседования)", "type": "User", "userSelectionMode": "PeopleOnly", "allowMultiple": true } ] } diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/sections/ApplicationSection.tsx b/src/webparts/requestPortal/forms/RecruitingSelection/sections/ApplicationSection.tsx index 5de503b..4f7e054 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/sections/ApplicationSection.tsx +++ b/src/webparts/requestPortal/forms/RecruitingSelection/sections/ApplicationSection.tsx @@ -1,39 +1,85 @@ import * as React from 'react'; -import { CollapseSection, FormField, TextInput, TextArea, Toggle, PeopleField } from '../../../shared/ui'; -import { ISectionProps, PERSON_PLACEHOLDER } from '../model'; +import { CollapseSection, FormField, TextInput, Select, PeopleField } from '../../../shared/ui'; +import { CompanyPickerMulti, Project1CPicker } from '../../../shared/dictionary'; +import { + ISectionProps, + PERSON_PLACEHOLDER, + OPEN_REASON_OPTIONS, + OPEN_REASON_REPLACE, + OPEN_REASON_TRANSFER, + OPEN_REASON_NEW +} from '../model'; -export const ApplicationSection: React.FC = ({ data, set, context }) => ( - - - set('Responsible', v)} - placeholder={PERSON_PLACEHOLDER} - /> - - - set('SubmitDate', v)} /> - - - set('ClosingDeadline', v)} - /> - - -