Adapt preparation presentation to declared applicability
This commit is contained in:
@@ -2,11 +2,14 @@ import { Link } from '@inertiajs/react';
|
||||
import type { RequirementsAssessment } from '@/lib/investor-context';
|
||||
import { card } from '@/pages/investment/shared';
|
||||
|
||||
export default function InvestmentRequirements({assessment, contextId}: {assessment?: RequirementsAssessment | null; contextId: string}) {
|
||||
export default function InvestmentRequirements({assessment, contextId, excludedSteps = []}: {assessment?: RequirementsAssessment | null; contextId: string; excludedSteps?: string[]}) {
|
||||
if (!assessment?.requirements.length) return null;
|
||||
const labels: Record<string,string> = {selected:'Localização escolhida; direito não inferido',missing:'Informação em falta',conditional:'Conforme as condições do projecto',declared:'Actividades declaradas; enquadrar modalidade',undetermined:'Procedimento específico por determinar'};
|
||||
const groups = new Map<string, RequirementsAssessment['requirements']>();
|
||||
for (const row of assessment.requirements) groups.set(row.opportunity_key,[...(groups.get(row.opportunity_key)??[]),row]);
|
||||
for (const row of assessment.requirements) {
|
||||
if (excludedSteps.includes(row.step)) continue;
|
||||
groups.set(row.opportunity_key,[...(groups.get(row.opportunity_key)??[]),row]);
|
||||
}
|
||||
return <section className="space-y-4" aria-label="Regras e documentos por oportunidade"><h2 className="text-xl font-bold">Requisitos por oportunidade e contexto</h2>
|
||||
<p>{assessment.fiscal_notice}</p>
|
||||
{[...groups.entries()].map(([key, rows])=><details key={key} className={card}><summary className="cursor-pointer font-semibold">{rows[0].opportunity_title} · {rows.length} aspectos a conferir</summary>{rows.map(r=><article key={r.opportunity_key+':'+r.code} className="my-3 space-y-2 border-t pt-3">
|
||||
|
||||
@@ -316,7 +316,15 @@ function makeSections(
|
||||
preparation.calculation_notice,
|
||||
preparation.notice,
|
||||
);
|
||||
for (const requirement of preparation.requirements ?? [])
|
||||
const omitted = (preparation.requirements ?? []).filter(
|
||||
(requirement: { state: string }) => requirement.state === 'not_applicable',
|
||||
);
|
||||
if (omitted.length)
|
||||
section?.paragraphs.push(
|
||||
`Não exigido neste contexto: ${omitted.map((requirement: { label: string; reason: string }) => `${requirement.label} (${requirement.reason})`).join('; ')}.`,
|
||||
);
|
||||
for (const requirement of preparation.requirements ?? []) {
|
||||
if (requirement.state === 'not_applicable') continue;
|
||||
section?.rows.push({
|
||||
field: requirement.label,
|
||||
value:
|
||||
@@ -331,6 +339,7 @@ function makeSections(
|
||||
classification:
|
||||
'Preparação informativa — simulação, sem submissão à Administração',
|
||||
});
|
||||
}
|
||||
}
|
||||
if (zone?.href)
|
||||
section?.rows.push({
|
||||
|
||||
@@ -531,7 +531,7 @@ export default function InvestmentPath(path: Path) {
|
||||
/>
|
||||
)}
|
||||
{!!path.investment_context?.opportunity_choices?.length && <OpportunityChoices choices={path.investment_context.opportunity_choices}/>}
|
||||
<InvestmentRequirements assessment={path.investment_context?.requirements_assessment} contextId={path.case.id}/>
|
||||
<InvestmentRequirements assessment={path.investment_context?.requirements_assessment} contextId={path.case.id} excludedSteps={path.steps.filter((step) => !step.preparation_allowed).map((step) => step.code)}/>
|
||||
{!!path.content_sources?.length && (
|
||||
<section
|
||||
className="space-y-2 rounded-xl border p-4"
|
||||
@@ -569,15 +569,14 @@ export default function InvestmentPath(path: Path) {
|
||||
<h2 className="font-semibold">Próxima acção</h2>
|
||||
{path.next ? (
|
||||
<a className="underline" href={path.next.href}>
|
||||
{path.next.action}: {path.next.code} · {path.next.title}
|
||||
{path.next.action}: {path.next.title}
|
||||
</a>
|
||||
) : (
|
||||
<p>Reveja as pendências e o acompanhamento.</p>
|
||||
)}
|
||||
<p className="text-sm">
|
||||
Pode preparar etapas independentes enquanto aguarda
|
||||
informação. Percurso v{path.definition_version}; os outros
|
||||
roteiros mantêm a numeração original.
|
||||
informação. As etapas abaixo adaptam-se às suas escolhas.
|
||||
</p>
|
||||
</section>
|
||||
<nav
|
||||
@@ -686,14 +685,25 @@ export default function InvestmentPath(path: Path) {
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
{Object.entries(path.phases).map(([number, label]) => (
|
||||
{path.steps.some((step) => !step.preparation_allowed) && (
|
||||
<section className="rounded-xl border p-4" aria-label="Etapas sem aplicação">
|
||||
<h2 className="font-semibold">Não precisa de preparar neste contexto</h2>
|
||||
<ul>
|
||||
{path.steps.filter((step) => !step.preparation_allowed).map((step) => (
|
||||
<li key={step.code}>{step.title}: {step.reason || 'Conforme as escolhas guardadas.'}</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="text-sm">Pode rever estas escolhas acima. Os dados e o histórico destas etapas ficam conservados.</p>
|
||||
</section>
|
||||
)}
|
||||
{Object.entries(path.phases).filter(([number]) => path.steps.some((step) => step.phase === Number(number) && step.preparation_allowed)).map(([number, label]) => (
|
||||
<section className="space-y-3" key={number}>
|
||||
<h2 className="text-lg font-semibold">
|
||||
Fase {number} · {label}
|
||||
</h2>
|
||||
<div className="grid items-start gap-3 md:grid-cols-2">
|
||||
{path.steps
|
||||
.filter((step) => step.phase === Number(number))
|
||||
.filter((step) => step.phase === Number(number) && step.preparation_allowed)
|
||||
.map((step) => (
|
||||
<Stage
|
||||
key={step.code}
|
||||
|
||||
Reference in New Issue
Block a user