import { Head } from '@inertiajs/react'; import { useState } from 'react'; import { PageTitle, Panel } from '@/components/procurement'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; type Outcome = 'admit' | 'exclude' | 'clarify'; type Review = { actor: number; decision: 'approve' | 'return'; reason: string }; type Attempt = { number: number; supplier: string; outcome: Outcome; reason: string; roles: string[]; required: number; reviews: Review[]; }; const reviewers = [ { id: 1, name: 'Conferente financeiro A', role: 'finance' }, { id: 2, name: 'Conferente financeiro B', role: 'finance' }, { id: 3, name: 'Chefia do departamento', role: 'department_head' }, ]; const roles: Record = { finance: 'Finanças', department_head: 'Chefia do departamento', }; const outcomes: Record = { admit: 'Admitir a proposta', exclude: 'Excluir a proposta', clarify: 'Solicitar esclarecimento', }; const selectClass = 'h-10 w-full rounded-md border bg-background px-3 text-sm'; const state = (attempt: Attempt) => attempt.reviews.some((review) => review.decision === 'return') ? 'Devolvida para revisão' : attempt.reviews.length >= attempt.required ? 'Decisão confirmada na simulação' : 'Aguarda conferência independente'; export default function AdmissionProposal() { const [selectedRoles, setSelectedRoles] = useState([]); const [required, setRequired] = useState(''); const [supplier, setSupplier] = useState('Concorrente A'); const [outcome, setOutcome] = useState('admit'); const [reason, setReason] = useState(''); const [considered, setConsidered] = useState(false); const [attempt, setAttempt] = useState(null); const [history, setHistory] = useState([]); const [reviewReasons, setReviewReasons] = useState>( {}, ); const eligible = reviewers.filter((reviewer) => selectedRoles.includes(reviewer.role), ); const admissionReady = supplier === 'Concorrente A'; const valid = selectedRoles.length > 0 && Number(required) >= 1 && Number(required) <= eligible.length && reason.trim().length >= 10 && considered && (outcome !== 'admit' || admissionReady); const final = attempt !== null && (attempt.reviews.some((review) => review.decision === 'return') || attempt.reviews.length >= attempt.required); const propose = () => { if (valid) { setAttempt({ number: history.length + 1, supplier, outcome, reason, roles: [...selectedRoles], required: Number(required), reviews: [], }); setReviewReasons({}); } }; const review = (actor: number, decision: Review['decision']) => { if ( !attempt || final || attempt.reviews.some((entry) => entry.actor === actor) || !reviewers.some( (entry) => entry.id === actor && attempt.roles.includes(entry.role), ) || (reviewReasons[actor] ?? '').trim().length < 10 ) return; setAttempt({ ...attempt, reviews: [ ...attempt.reviews, { actor, decision, reason: reviewReasons[actor].trim() }, ], }); }; const next = () => { if (attempt) setHistory([...history, structuredClone(attempt)]); setAttempt(null); setReason(''); setConsidered(false); setReviewReasons({}); }; return ( <>
Demonstração com intervenientes e concorrentes fictícios. Não guarda dados, publica políticas, exclui fornecedores ou altera adjudicações. Simular outro conferente não autentica outra pessoa.
Perfis de conferência admitidos pela política {Object.entries(roles).map(([value, label]) => ( ))}

{eligible.length} intervenientes fictícios elegíveis com os perfis seleccionados. Uma mesma pessoa conta apenas uma vez.

{required && Number(required) > eligible.length && (

Não existem intervenientes elegíveis suficientes para a quantidade escolhida.

)}

Base fictícia: requisitos v1. O caso A tem análise sem pendências assinaladas; o caso B tem requisito obrigatório não cumprido; o caso C tem pendência ou divergência. “Solicitar esclarecimento” não envia mensagens.

{outcome === 'admit' && !admissionReady && (

Neste primeiro âmbito proposto, a admissão aguarda resolução das pendências, divergências ou requisitos obrigatórios não cumpridos. Não se propõe uma dispensa automática.

)}