Files
Investidor-V2/resources/js/lib/opportunity-fill-flow.ts
T

153 lines
4.2 KiB
TypeScript

export type FillGroup = {
id: string;
title: string;
hint: string;
fields: string[];
};
const definitions: Omit<FillGroup, 'fields'>[] = [
{
id: 'idea',
title: 'Ideia e actividade',
hint: 'Identifique o investimento e descreva a necessidade que pretende responder.',
},
{
id: 'people',
title: 'Promotor e contactos',
hint: 'Reutilize os contactos guardados e escolha o que pode ser divulgado.',
},
{
id: 'territory',
title: 'Localização e enquadramento',
hint: 'Indique o território conhecido e as associações documentadas que se aplicam.',
},
{
id: 'operation',
title: 'Actividade e impacto',
hint: 'Complete os produtos, recursos, mercados e impactos relevantes para esta oportunidade.',
},
{
id: 'finance',
title: 'Investimento e financiamento',
hint: 'Preencha os valores conhecidos. O rascunho pode continuar incompleto.',
},
{
id: 'evidence',
title: 'Documentos e imagens',
hint: 'Reutilize os recursos guardados na mesma oportunidade.',
},
{
id: 'specific',
title: 'Dados específicos',
hint: 'Preencha os detalhes aplicáveis à modalidade escolhida.',
},
{
id: 'review',
title: 'Revisão e divulgação',
hint: 'Reveja riscos, condições e visibilidade antes das acções autorizadas de submissão.',
},
];
const fields: Record<string, string[]> = {
idea: [
'official_title',
'sector_id',
'subsector_id',
'economic_activity_id',
'executive_summary',
'demand_statement',
'opportunity_type',
'maturity_stage',
'enterprise_size',
],
people: [
'promoter_type',
'internal_contact_id',
'publish_contact',
'public_contact_id',
],
territory: [
'location_mode',
'geographic_scope',
'multi_district_rationale',
'locations',
'relations',
],
operation: [
'investment_modalities',
'investor_profiles',
'products',
'assets',
'inputs',
'markets',
'competitive_advantage',
'employment',
'impact_indicators',
],
finance: [
'total_investment',
'currency',
'investment_breakdown',
'secured_financing',
'funding_sought',
'financial_indicators',
],
evidence: ['documents', 'evidences', 'images'],
review: [
'publication_languages',
'visibility',
'review_due_date',
'truth_declaration',
'milestones',
'licenses',
'environmental_social',
'risks',
],
};
/** Presentation groups only: retain every applicable field exactly once, including future schema keys. */
export function opportunityFillGroups(available: string[]): FillGroup[] {
const unique = [...new Set(available)];
return definitions
.map((group) => ({
...group,
fields: unique.filter((field) => {
const owner =
Object.keys(fields).find((key) =>
fields[key].includes(field),
) ?? 'specific';
return owner === group.id;
}),
}))
.filter((group) => group.fields.length > 0);
}
export function opportunityErrorGroup(
groups: FillGroup[],
errors: Record<string, string>,
): string | undefined {
return groups.find((group) =>
group.fields.some((field) =>
Object.keys(errors).some(
(path) =>
path === `canonical.${field}` ||
path.startsWith(`canonical.${field}.`),
),
),
)?.id;
}
export function opportunityMissingGroups(
groups: FillGroup[],
paths: string[],
): FillGroup[] {
return groups.filter((group) =>
group.fields.some((field) =>
paths.some((path) => {
const normalized = path.replace(/^canonical\./, '');
return (
normalized === field || normalized.startsWith(`${field}.`)
);
}),
),
);
}