import { FormEvent, useEffect, useState } from "react"; import { dateValueToMonthInput, monthInputToDateValue } from "../lib/format"; import type { ActivityType, EvaluatorSummary, WorkItemCreatePayload, WorkItemFormOptions } from "../lib/types"; import { WORK_TYPE_OPTIONS } from "../lib/work-types"; import { collectRegistrationGroups, DEFAULT_REGISTRATION_GROUP, fieldUsesIndividualScope, hasIndividualScope, normalizeRegistrationGroup, propertyHasContent, REGISTRATION_OPERATIONAL_SCOPE_FIELDS, ScopeField, seedPropertyRegistrationDetailsFromWorkItem, setPayloadFieldScope, } from "../lib/work-item-form"; import { WORK_UNIT_OPTIONS, normalizeWorkUnit } from "../lib/work-units"; const OTHER_OPTION = "__other__"; const operationalScopeOptions: Array<{ field: ScopeField; label: string }> = [ { field: "schedule_forecast", label: "Previsão de cronograma" }, { field: "priority", label: "Prioridade" }, { field: "process_due_date", label: "Prazo final" }, { field: "sei_due_date", label: "Prazo SEI" }, { field: "sei_sent_date", label: "Envio ao SEI" }, { field: "work_type", label: "Tipo do trabalho" }, { field: "work_product_number", label: "Numeração" }, { field: "support_reference", label: "Referência de apoio" }, ]; const assignmentScopeOptions: Array<{ field: ScopeField; label: string }> = [ { field: "evaluator", label: "Avaliador" }, { field: "evaluator_due_date", label: "Prazo do avaliador" }, ]; const modelScopeOptions: Array<{ field: ScopeField; label: string }> = [ { field: "model", label: "Modelo" }, ]; type WorkItemFormProps = { mode: "create" | "edit"; initialValue: WorkItemCreatePayload; activityTypes: ActivityType[]; evaluators: EvaluatorSummary[]; formOptions: WorkItemFormOptions; saving: boolean; error: string; onSubmit: (payload: WorkItemCreatePayload) => Promise; }; function normalizeNullableText(value: string | null | undefined) { const trimmed = (value ?? "").trim(); return trimmed || null; } function CatalogField({ label, value, options, onChange, }: { label: string; value: string | null; options: string[]; onChange: (value: string | null) => void; }) { const [isCustom, setIsCustom] = useState(() => Boolean(value && !options.includes(value))); useEffect(() => { setIsCustom(Boolean(value && !options.includes(value))); }, [options, value]); const selectValue = isCustom ? OTHER_OPTION : value ? value : ""; return (
{isCustom ? ( ) : null}
); } function ScopeStatusChip({ label, individual, onClick, }: { label: string; individual: boolean; onClick: () => void; }) { return ( ); } function joinLabels(labels: string[]) { if (labels.length === 0) return ""; if (labels.length === 1) return labels[0]; if (labels.length === 2) return `${labels[0]} e ${labels[1]}`; return `${labels.slice(0, -1).join(", ")} e ${labels[labels.length - 1]}`; } export function WorkItemForm({ mode, initialValue, activityTypes, evaluators, formOptions, saving, error, onSubmit, }: WorkItemFormProps) { const [form, setForm] = useState(initialValue); useEffect(() => { setForm(initialValue); }, [initialValue]); const registrationGroupListId = `registration-groups-${mode}`; const registrationGroups = collectRegistrationGroups(form.properties); const usesIndividualOperationalDetails = hasIndividualScope(form.field_scopes, REGISTRATION_OPERATIONAL_SCOPE_FIELDS); const usesIndividualModelDetails = usesIndividualField("model"); const individualOperationalLabels = operationalScopeOptions.filter((option) => usesIndividualField(option.field)).map((option) => option.label); const individualAssignmentLabels = assignmentScopeOptions.filter((option) => usesIndividualField(option.field)).map((option) => option.label); function usesIndividualField(fieldName: ScopeField) { return fieldUsesIndividualScope(form.field_scopes, fieldName); } function updateField(key: K, value: WorkItemCreatePayload[K]) { setForm((current) => ({ ...current, [key]: value })); } function updateProperty( index: number, updater: (property: WorkItemCreatePayload["properties"][number]) => WorkItemCreatePayload["properties"][number], ) { setForm((current) => ({ ...current, properties: current.properties.map((item, itemIndex) => (itemIndex === index ? updater(item) : item)), })); } function updateScope(fieldName: ScopeField, checked: boolean) { setForm((current) => { const nextForm = { ...current, field_scopes: { ...current.field_scopes } }; setPayloadFieldScope(nextForm, fieldName, checked ? "individual" : "shared"); return nextForm; }); } async function handleSubmit(event: FormEvent) { event.preventDefault(); const normalizedModelStatus = normalizeNullableText(form.model_status) ?? "analisar"; const payload: WorkItemCreatePayload = { ...form, origin: normalizeNullableText(form.origin), request_type: normalizeNullableText(form.request_type), purpose: normalizeNullableText(form.purpose), priority: normalizeNullableText(form.priority), model_status: normalizedModelStatus, entry_unit: normalizeWorkUnit(form.entry_unit), model_name: normalizedModelStatus === "sim" || normalizedModelStatus === "talvez" ? normalizeNullableText(form.model_name) : null, model_solution: normalizedModelStatus === "nao" ? normalizeNullableText(form.model_solution) : null, model_notes: normalizeNullableText(form.model_notes), notes_summary: normalizeNullableText(form.notes_summary), properties: form.properties .filter((item) => propertyHasContent(item)) .map((item) => { const propertyModelStatus = normalizeNullableText(item.model_status) ?? "analisar"; return { ...item, model_status: propertyModelStatus, model_name: propertyModelStatus === "sim" || propertyModelStatus === "talvez" ? normalizeNullableText(item.model_name) : null, model_solution: propertyModelStatus === "nao" ? normalizeNullableText(item.model_solution) : null, model_notes: normalizeNullableText(item.model_notes), }; }), planned_activities: form.planned_activities.filter((item) => item.activity_type_id > 0), }; await onSubmit(payload); } return (

Dados do processo

updateField("origin", value)} /> updateField("request_type", value)} />
updateField("purpose", value)} />

Compartilhamento entre inscrições

Por padrão, tudo começa no processo. Clique em um campo apenas quando ele precisar ser preenchido por inscrição.

A data de entrada sempre pertence ao processo.

{[...operationalScopeOptions, ...assignmentScopeOptions, ...modelScopeOptions].map((option) => ( updateScope(option.field, !usesIndividualField(option.field))} /> ))}

Observações gerais