import { Head } from '@inertiajs/react'; import { Plus, RotateCcw } from 'lucide-react'; import { useState } from 'react'; import { PageTitle, Panel } from '@/components/procurement'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; type Criterion = { id: number; label: string; category: string; required: boolean; }; type Finding = { result: 'pending' | 'met' | 'not_met' | 'not_applicable'; evidence: string; reason: string; }; type Answers = Record; type Version = { number: number; criteria: Criterion[]; answers: Answers }; const suppliers = ['Concorrente A', 'Concorrente B', 'Concorrente C']; const initialCriteria: Criterion[] = [ { id: 1, label: 'Documento definido pela empresa para este processo', category: 'administrative', required: false, }, { id: 2, label: 'Conformidade com a especificação definida no processo', category: 'technical', required: false, }, ]; const categories: Record = { legal: 'Jurídica', financial: 'Económico-financeira', fiscal: 'Fiscal', technical: 'Técnica', administrative: 'Administrativa', }; const results: Record = { pending: 'Por analisar', met: 'Cumprido', not_met: 'Não cumprido', not_applicable: 'Não aplicável', }; const emptyFinding: Finding = { result: 'pending', evidence: '', reason: '' }; const key = (criterion: number, supplier: number) => `${criterion}-${supplier}`; const complete = (finding: Finding) => finding.result !== 'pending' && finding.reason.trim().length >= 10 && (finding.result === 'not_applicable' || finding.evidence.trim().length >= 3); const selectClass = 'h-10 w-full rounded-md border bg-background px-3 text-sm'; export default function QualificationProposal() { const [criteria, setCriteria] = useState(initialCriteria); const [answers, setAnswers] = useState({}); const [started, setStarted] = useState(false); const [version, setVersion] = useState(1); const [history, setHistory] = useState([]); const [nextId, setNextId] = useState(3); const validCriteria = criteria.length > 0 && criteria.every((criterion) => criterion.label.trim().length >= 3) && new Set( criteria.map((criterion) => criterion.label.trim().toLocaleLowerCase('pt-PT'), ), ).size === criteria.length; const updateCriterion = (id: number, change: Partial) => setCriteria( criteria.map((criterion) => criterion.id === id ? { ...criterion, ...change } : criterion, ), ); const finding = (criterion: number, supplier: number) => answers[key(criterion, supplier)] ?? emptyFinding; const updateFinding = ( criterion: number, supplier: number, change: Partial, ) => setAnswers({ ...answers, [key(criterion, supplier)]: { ...finding(criterion, supplier), ...change, }, }); const revise = () => { setHistory([ ...history, { number: version, criteria: criteria.map((criterion) => ({ ...criterion })), answers: structuredClone(answers), }, ]); setVersion(version + 1); setStarted(false); setAnswers({}); }; const reset = () => { setCriteria(initialCriteria); setAnswers({}); setStarted(false); setVersion(1); setHistory([]); setNextId(3); }; return ( <>
Repor exemplos } />
Esta demonstração usa concorrentes fictícios e não guarda dados. Os dois requisitos iniciais são exemplos editáveis. Nenhuma escolha aqui altera fornecedores, pontuações ou adjudicações da aplicação.
{criteria.map((criterion) => (
{!started && ( )}
))}
{started ? ( ) : ( <> )}
{!validCriteria && (

Defina pelo menos um requisito com um nome distinto de três ou mais caracteres.

)}
{!started ? (

Defina os requisitos e inicie a simulação para preencher a análise.

) : (
{criteria.map((criterion) => (

{criterion.label}

{categories[criterion.category]} ·{' '} {criterion.required ? 'Declarado obrigatório neste exemplo' : 'Sem obrigatoriedade declarada'}

{suppliers.map((supplier, index) => { const answer = finding( criterion.id, index, ); return (

{supplier}