153 lines
4.2 KiB
TypeScript
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}.`)
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}
|